boost :: enable_if不在函数签名中

Lor*_*one 7 c++ sfinae c++11

这只是一个关于样式的问题:我不喜欢C++模板元编程的方式,它要求你使用返回类型或为SFINAE的技巧添加额外的伪参数.所以,我提出的想法是将SFINAE事物放在模板参数定义本身中,如下所示:

#include <iostream>
#include <boost/type_traits/is_array.hpp>
#include <boost/utility/enable_if.hpp>
using namespace std;

template <typename T, typename B=typename boost::enable_if< boost::is_array<T> >::type > void asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T, typename B=typename boost::disable_if< boost::is_array<T> >::type > void asd(){
    cout<<"This is for NON arrays"<<endl;
}

int main() {
    asd<int>();
    asd<int[]>();
}
Run Code Online (Sandbox Code Playgroud)

这个例子让g ++抱怨:

../src/afg.cpp:10:97:错误:重新定义'template void asd()'

SFINAE就在那里工作,因为如果我删除例如一个disable_if,编译错误是:

../src/afg.cpp:15:12:错误:没有匹配函数来调用'asd()'

这就是我想要的.

那么,有没有办法在一个函数的"正常"签名中完成SFINAE,即返回类型+参数列表?

编辑:这最终我将在真正的代码中尝试:

#include <iostream>
#include <type_traits>
using namespace std;

template <typename T, typename enable_if< is_array<T>::value, int >::type =0 > void asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T, typename enable_if< !is_array<T>::value, int >::type =0 > void asd(){
    cout<<"This is for NON arrays"<<endl;
}

int main() {
    asd<int[]>();
    asd<int>();
}
Run Code Online (Sandbox Code Playgroud)

我使用c ++ 0x的东西而不是boost,因为只要我需要c ++ 0x来使用模板参数的默认值,我认为没有理由使用boost,这是它的前身.

Pau*_* II 9

好吧,我通常使用这些宏来使enable_if构造更清晰(它们甚至可以在大多数C++ 03编译器中工作):

#define ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE(...) __VA_ARGS__>::type
#define FUNCTION_REQUIRES(...) typename boost::enable_if<boost::mpl::and_<__VA_ARGS__, boost::mpl::bool_<true> >, ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE
#define EXCLUDE(...) typename boost::mpl::not_<typename boost::mpl::or_<__VA_ARGS__, boost::mpl::bool_<false> >::type >::type
Run Code Online (Sandbox Code Playgroud)

然后你会像这样定义你的函数:

template <typename T >
FUNCTION_REQUIRES(is_array<T>)
(void) asd(){
    cout<<"This is for arrays"<<endl;
}

template <typename T >
FUNCTION_REQUIRES(EXCLUDE(is_array<T>))
(void) asd(){
    cout<<"This is for NON arrays"<<endl;
}
Run Code Online (Sandbox Code Playgroud)

唯一的问题是,你需要在返回类型周围加上括号.如果你忘了它们,编译器会说'ERROR_PARENTHESIS_MUST_BE_PLACED_AROUND_THE_RETURN_TYPE'这样的东西是未定义的.


Luc*_*ton 8

由于C++ 11使它成为可能,我只是在模板参数中使用enable_if(或相反disable_if),就像你正在做的那样.如果/当有多个重载时,我使用虚拟的,默认的模板参数,这使得模板参数列表在arity中有所不同.所以重用你的例子:

template<
    typename T
    , typename B = typename boost::enable_if<
        boost::is_array<T>
    >::type
>
void asd() {
    cout << "This is for arrays" << endl;
}

template<
    typename T
    , typename B = typename boost::disable_if<
        boost::is_array<T>
    >::type
    , typename = void
>
void asd() {
    cout << "This is for arrays" << endl;
}
Run Code Online (Sandbox Code Playgroud)

另一种不弄乱返回类型(在某些情况下不可用,例如转换运算符)的替代方法是从C++ 03开始使用默认参数:

template<typename T>
void
foo(T t, typename std::enable_if<some_trait<T>::value>::type* = nullptr);
Run Code Online (Sandbox Code Playgroud)

我不使用这种形式,因为我不喜欢与参数类型"混乱"和返回类型一样多,并且出于一致性原因(因为在所有情况下都不可行).


Joh*_*itb 6

默认模板参数不是函数模板签名的一部分.但模板参数的类型是.所以你可以做以下事情,并能够超载它

template <
  typename T,
  typename boost::enable_if< 
    boost::is_array<T>, int 
  >::type = 0
> 
void asd() {
    cout<<"This is for arrays"<<endl;
}

template <
  typename T, 
  typename boost::disable_if< 
    boost::is_array<T>, int 
  >::type = 0 
>
void asd() {
    cout<<"This is for arrays"<<endl;
}
Run Code Online (Sandbox Code Playgroud)