我预计以下会形成NDR,但似乎不是:-(
#include <type_traits>
template <typename T, typename Enabler = void>
struct is_complete : std::false_type {};
template <typename T>
struct is_complete<T, std::void_t<decltype(sizeof(T) != 0)>> : std::true_type {};
class X;
static_assert(!is_complete<X>::type{}); // incomplete type
class X {};
static_assert(!is_complete<X>::type{}); // complete, but already instantiated
注意:假设 sizeof(T) != 0
对完整性特征有效(因为没有类型可以有 sizeof(T) == 0
,使用其他常量会强制为特征找到更好的名称:-))
它是来自Is a specialization implicitly instantiated if it has already been implicitly instantiated?的代码的变体,其中程序已被声明为格式错误的程序,无需诊断(NDR),因为 method is_complete_helper<X>::test<X>
具有2种不同的含义,具体取决于实例化的点 .
看起来差不多的参考文件使程序形成错误,但并不像我所理解的那样:
在假设实例化中对这种构造的解释不同于在模板的任何实际实例化中对相应构造的解释 .
函数模板,成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元中具有多个实例化点,并且除了上述实例化的点之外,对于任何实例 . 在翻译单元内具有实例化点的这种专门化,翻译单元的末尾也被认为是实例化的点 . 类模板的专门化在翻译单元中最多只有一个实例化点 . 任何模板的专门化可以在多个翻译单元中具有实例化点 . 如果两个不同的实例化点根据单定义规则给出模板特化不同的含义,则程序形成错误,不需要诊断 .
我错了 ?或者不幸的是这个程序是正确的 .
1 回答
您不能使用程序编译(并运行)作为其不是格式错误的证据,NDR . 以同样的方式,你不能使用看似有效的程序输出来证明它没有表现出未定义的行为 .
也就是说,这里的相关规则是[temp.point]/8:
我们只有一点
is_complete<X>
的实例化:它就在第一个static_assert
之前 . 所以,这是"fine" - 它是's arguably confusing and bad, but it'的良好形式 .但是,如果我们将其拆分:
现在这是不正确的,不需要诊断 .
注意,您不需要
sizeof(T) != 0
. 只是sizeof(T)
很好 . 您不能采用sizeof
的不完整类型,因此您只需检查sizeof(T)
是否为有效表达式 .