继承和 is_detected_v 提供了一个奇怪的结果 (C++17)

Inheritance and is_detected_v provides a strange result (C++17)

我有简化版的代码:

#include <experimental/type_traits>

template<class T> using has_data_t = decltype(T::data());

template <class B> constexpr auto get_data() {
    return std::experimental::is_detected_v<has_data_t, B>;
}
    
template <typename Topt> struct opt_base {
    static constexpr bool i = get_data<Topt>();
  //static constexpr auto j = get_data<Topt>(); // fail to compile
};

struct opt : public opt_base<opt> {
    static int data() { return 7;}
};

int main() {
    static_assert(std::experimental::is_detected_v<has_data_t, opt>);
}

此代码编译通过。但是,如果您取消注释注释行,则断言失败。它使用 GCC 7.1 和 Clang 4.0.0 进行了测试。编译参数:-std=c++1z -O3 -Wall。 Demo

在此代码中:

static constexpr bool i = get_data<Topt>();
static constexpr auto j = get_data<Topt>();

Topt(即 opt)尚未完成。所以 is_detected_v<has_data_t, opt> 应该是 false。但是当我们到达 main 时,opt 完成。所以我们期望 is_detected_v<has_data_t, opt>true.

拥有一个在不同上下文中实例化时会产生不同结果的模板意味着您的程序格式错误,不需要诊断。见 [temp.point]:

A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

添加 j 并不重要 - 它只是碰巧翻转了开关,改变了编译器选择实例化事物的方式的顺序。无论 j 是否存在,该程序都是病式的。