有许多方法可以触发SFINAE,其中enable_if
只是其中之一。
首先:
什么是std::enable_if?
它只是这样的:
template<bool, class T=void> enable_if{ typedef T type; };
template<class T> enable_if<false,T> {};
template<bool b, class T=void> using enable_if_t = typename enable_f<b,T>::type;
这个想法是使typename enable_if<false>::type
成为一个错误,从而跳过包含它的任何模板声明。
那么这如何触发函数选择呢?
禁用函数
这个想法是在某些部分使声明出错:
按返回类型
template<class Type>
std::enable_if_t<cond<Type>::value,Return_type> function(Type);
通过实参
template<class Type>
return_type function(Type param, std::enable_if_t<cond<Type>::value,int> =0)
通过模板参数
template<class Type,
std::enable_if_t<cond<Type>::value,int> =0> //note the space between > and =
return_type function(Type param)
选择函数
您可以使用类似这样的技巧来参数化不同的替代方案:
tempplate<int N> struct ord: ord<N-1>;
struct ord<0> ;
template<class T, std::enable_if<condition3, int> =0>
retval func(ord<3>, T param)
template<class T, std::enable_if<condition2, int> =0>
retval func(ord<2>, T param)
template<class T, std::enable_if<condition1, int> =0>
retval func(ord<1>, T param)
template<class T>
retval func(ord<0>, T param)
template<class T>
retval func(T param) ,param); }
如果满足condition3
,则会调用第一个/第二个/第三个/第四个函数,然后是condition2
,然后是condition1
,最后是没有条件。
其他SFINAE触发器
编写编译时条件可以是显式特化的问题,也可以是未评估表达式成功/失败的问题:
例如:
template<class T, class = void>
struct is_vector: std::false_type {}
template<class X>
struct is_vector<vector<X> >:: std::true_type {}
所以is_vector<int>::value
应该为false
,但is_vecttor<vector<int> >::value
应该为true
或者通过内省来实现,如
template<class T>
struct is_container<class T, class = void>: std::false_type {};
template<class T>
struct is_container<T, decltype(
std::begin(std::declval<T>()),
std::end(std::declval<T>()),
std::size(std::declval<T>()),
void(0))>: std::true_type {};
这样做,is_container<X>::value
将在给定X x
时为true
,您可以编译std::begin(x)
等。
关键是,如果所有子表达式都可编译,则decltype(...)
实际上是void
(逗号运算符会丢弃先前的表达式)。
甚至可能有许多其他选择。希望在这一切之间,您能找到一些有用的东西。
A<6> a6{a4};
是(打算)调用类似于复制构造函数的函数,我想使用SFINAE。因此,参数必须是一种类型,而不是A<4>::operator()
的结果,就像您的A<6> a6(a4())
一样。 - Walter