什么时候对enable_if_t表达式进行评估?

Car*_*nta 2 c++

这是我的代码:

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版本.

Bar*_*rry 5

一切都在编译时进行评估.当您调用时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无法在该上下文中进行评估.