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

时间:2017-05-04 22:37:46

标签: c++ templates 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

1 个答案:

答案 0 :(得分:7)

在此代码中:

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]:

  

任何模板的特化都可能在多个翻译单元中具有实例化点。如果两个不同的实例化点根据单定义规则给出模板特化的不同含义,则程序格式错误,无需诊断。

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