Wal*_*ter 25 c++ constructor sfinae c++11
在模板元编程中,可以在返回类型上使用SFINAE 来选择某个模板成员函数,即
template<int N> struct A {
int sum() const noexcept
{ return _sum<N-1>(); }
private:
int _data[N];
template<int I> typename std::enable_if< I,int>::type _sum() const noexcept
{ return _sum<I-1>() + _data[I]; }
template<int I> typename std::enable_if<!I,int>::type _sum() const noexcept
{ return _data[I]; }
};
Run Code Online (Sandbox Code Playgroud)
但是,这对构造函数不起作用.假设,我想声明构造函数
template<int N> struct A {
/* ... */
template<int otherN>
explicit(A<otherN> const&); // only sensible if otherN >= N
};
Run Code Online (Sandbox Code Playgroud)
但不允许这样做otherN < N.
那么,SFINAE可以在这里使用吗?我只对允许自动模板参数扣除的解决方案感兴趣
A<4> a4{};
A<5> a5{};
A<6> a6{a4}; // doesn't compile
A<3> a3{a5}; // compiles and automatically finds the correct constructor
Run Code Online (Sandbox Code Playgroud)
注意:这是一个非常简单的例子,其中SFINAE可能过度并且static_assert可能就足够了.但是,我想知道我是否可以使用SFINAE.
Ker*_* SB 28
您可以向模板添加默认类型参数:
template <int otherN, typename = typename std::enable_if<otherN >= N>::type>
explicit A(A<otherN> const &);
Run Code Online (Sandbox Code Playgroud)
触发SFINAE的方法有很多,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;
Run Code Online (Sandbox Code Playgroud)
这个想法是使typename enable_if<false>::type成为一个错误,因此使包含它的任何模板声明都被跳过。
那么如何选择触发功能呢?
这个想法使声明在某种程度上是错误的:
template<class Type>
std::enable_if_t<cond<Type>::value,Return_type> function(Type);
Run Code Online (Sandbox Code Playgroud)
template<class Type>
return_type function(Type param, std::enable_if_t<cond<Type>::value,int> =0)
Run Code Online (Sandbox Code Playgroud)
template<class Type,
std::enable_if_t<cond<Type>::value,int> =0> //note the space between > and =
return_type function(Type param)
Run Code Online (Sandbox Code Playgroud)
您可以使用以下技巧来参数化不同的替代方案:
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> // default one
retval func(ord<0>, T param) { ... }
// THIS WILL BE THE FUCNTION YOU'LL CALL
template<class T>
retval func(T param) { return func(ord<9>{},param); } //any "more than 3 value"
Run Code Online (Sandbox Code Playgroud)
如果满足,将调用第一个/第二个/第三个/第四个函数condition3,condition2而condition1不是没有一个。
编写编译时条件可以是显式的专业问题,也可以是表达式的成功/失败未评估的问题:
例如:
template<class T, class = void>
struct is_vector: std::false_type {};
template<class X>
struct is_vector<vector<X> >:: std::true_type {};
Run Code Online (Sandbox Code Playgroud)
使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 {};
Run Code Online (Sandbox Code Playgroud)
这样is_container<X>::value就可以true了X x,您可以编译std::begin(x)等。
诀窍在于,只有所有子表达式都是可编译的,the decltype(...)实际上是void(,运算符将丢弃先前的表达式)。
甚至可以有许多其他选择。希望在这一切之间您能找到有用的东西。
在C++ 11中,您可以使用默认模板参数:
template <int otherN, class = typename std::enable_if<otherN >= N>::type>
explicit A(A<otherN> const &);
Run Code Online (Sandbox Code Playgroud)
但是,如果您的编译器还不支持默认模板参数,或者您需要多次重载,那么您可以使用这样的默认函数参数:
template <int otherN>
explicit A(A<otherN> const &, typename std::enable_if<otherN >= N>::type* = 0);
Run Code Online (Sandbox Code Playgroud)
可接受的答案在大多数情况下是好的,但如果存在两个具有不同条件的此类构造函数重载,则失败。在这种情况下,我也在寻找解决方案。
是:可接受的解决方案有效,但不适用于两个替代构造函数,例如,
template <int otherN, typename = typename std::enable_if<otherN == 1>::type>
explicit A(A<otherN> const &);
template <int otherN, typename = typename std::enable_if<otherN != 1>::type>
explicit A(A<otherN> const &);
Run Code Online (Sandbox Code Playgroud)
因为,如本页中所述,
一个常见的错误是声明两个函数模板,它们的默认模板参数仅不同。这是非法的,因为默认模板参数不是功能模板签名的一部分,并且声明两个具有相同签名的不同功能模板是非法的。
如同一页中所建议,您可以通过将SFINAE修改签名,应用于值(而非类型)模板参数的类型来解决此问题,如下所示
template <int otherN, typename std::enable_if<otherN == 1, bool>::type = true>
explicit A(A<otherN> const &);
template <int otherN, typename std::enable_if<otherN != 1, bool>::type = true>
explicit A(A<otherN> const &);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5909 次 |
| 最近记录: |