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

时间:2015-06-30 00:55:55

标签: 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);
}

由于std::enable_if_t<T::value != 1>要求我的value是静态的constexpr,我假设它在编译期间被评估(我需要确认)。但由于它是一个模板,它将取决于T,但我的主要内容也是如此,它们不是constexpr

int main() {
    test p;
    foo(p);
}

输出:

test

那么此时如何评估事物(包括函数的初始化顺序)呢?由于编译器需要决定创建哪个foo版本。

2 个答案:

答案 0 :(得分:5)

在编译时评估所有内容。当您调用foo(p)时,编译器将执行名称查找以查找foop。它会找到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);

然后它将尝试执行模板替换。请注意,模板替换失败不是错误(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{});

这将无法编译,并显示错误,指示foo没有匹配函数 - 两个重载模板替换都将失败,因为T::value无法在该上下文中进行评估。

答案 1 :(得分:2)

模板参数始终是在编译时严格评估的编译时实体。

在使用foo(p)的示例中,模板参数推导为T == test,这是在编译时完成的。知道T == test后,T::value的值称为test::value,其存在且是constexpr(在编译时也称为)。