这是我的代码:
template<class T, std::enable_if_t<T::value == 1> * = nullptr>
void foo(T) {
std::cout<<"test"<<std::endl;
} // #1
template<class T, std::enable_if_t<T::value != 1> * = nullptr>
void foo(T) {} // #2
class test{
public:
constexpr static int value = 1;
test() {}
};
int main() {
test p;
foo(p);
}
Run Code Online (Sandbox Code Playgroud)
因为std::enable_if_t<T::value != 1>要求我value是静态的constexpr,我假设它在编译期间被评估(我需要确认).但由于它是一个模板,它将取决于T,但我也在主要上有这个,它们不是constexpr:
int main() {
test p;
foo(p);
}
Run Code Online (Sandbox Code Playgroud)
输出:
test
Run Code Online (Sandbox Code Playgroud)
那么此时如何评估事物(包括函数的初始化顺序)呢?由于编译器需要决定创建哪个foo版本.
一切都在编译时进行评估.当您调用时foo(p),编译器将执行名称查找以查找内容foo和内容p.它会找到两个名字foo:
template<class T, std::enable_if_t<T::value == 1>* = nullptr>
void foo(T);
template<class T, std::enable_if_t<T::value != 1>* = nullptr>
void foo(T);
Run Code Online (Sandbox Code Playgroud)
然后它将尝试执行模板替换.请注意,模板替换失败不是错误(sfinae).T被推断为test,所以我们必须使用非类型模板参数.第一个有类型std::enable_if_t<T::value == 1>*.我们必须在此时评估是什么test::value.为了使替换成功,必须有一些value等于1的常量命名.如果没有命名value,或者它是类型,成员变量或不等于1,则替换将失败.在这种情况下,有一个static constexpr value是1,所以它成功了.
第二个重载失败模板扣除,因为没有enable_if<false>::type.
由于只有一个可行的过载,它是最好的可行过载,我们选择它.所有这些都是在编译时完成的.
请注意,如果你有类似的东西:
struct bad_test {
int value = 1;
};
foo(bad_test{});
Run Code Online (Sandbox Code Playgroud)
这将无法使用指示没有匹配函数的错误进行编译foo- 您的两个重载模板替换都将失败,因为T::value无法在该上下文中进行评估.