请考虑以下代码:
#include <iostream>
#include <type_traits>
template <typename T>
struct A {
int val = 0;
template <class = typename std::enable_if<T::value>::type>
A(int n) : val(n) {};
A(...) { }
/* ... */
};
struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };
int main() {
A<YES> y(10);
A<NO> n;
std::cout << "YES: " << y.val << std::endl
<< "NO: " << n.val << std::endl;
}
我想有选择地使用enable_if为某些类型定义构造函数A :: A(int)。对于所有其他类型,都有默认构造函数A :: A(...),当替换失败时,它应该是编译器的默认情况。但是这对我来说有意义编译器(gcc版本4.9.0 20130714)仍在抱怨
sfinae.cpp:实例化结构A&#39;:sfinae.cpp:19:11:
从这里需要sfinae.cpp:9:5:错误:没有名为&#39; type&#39;在
&#39; struct std :: enable_if&#39;
A(int n):val(n){};
这样的构造函数可能吗?是否可以使用其他构造函数(copy-constructor和move-constructor)?
答案 0 :(得分:36)
我认为这不能使用单个默认模板参数,因为在实例化类模板时需要解析其值。
我们需要将替换推迟到构造函数模板实例化的程度。一种方法是将模板参数默认为T并向构造函数添加额外的伪参数:
template<typename U = T>
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }
答案 1 :(得分:9)
通常这是使用匿名默认参数完成的:
A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};
击> <击> 撞击>
您不能将类中的模板参数用于SFINAE out方法。 所以一种方法是添加一个替换int的虚拟类型:
#include <iostream>
#include <type_traits>
template <typename T>
struct A {
int val = 0;
template<typename Integer
,typename = typename std::enable_if<T::value && sizeof(Integer)>::type
>
A(Integer n) : val(n) {};
A(...) {}
/* ... */
};
struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };
int main() {
A<YES> y(10);
A<NO> n;
std::cout << "YES: " << y.val << std::endl
<< "NO: " << n.val << std::endl;
}
这是有效的,因为您在构造函数中使用成员模板参数SFINAE,但测试始终为true,因此不会污染您的检查
答案 2 :(得分:0)
您只需将 requires
添加到模板即可实现:
template <typename U = T> requires U::value
A(int n) : val(n) { }
requires
子句获得一个constant expression
,其求值为true
或false
,从而决定是否在过载解析中考虑此方法,如果require子句为true,否则忽略它。