我希望以下内容会构成不良的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),作为方法 is_complete_helper<X>::test<X>
取决于实例化点,有两种不同的含义。
参考文献似乎会使程序格式错误,但据我所知并非如此:
在假设的实例中这种构造的解释不同于在模板的任何实际实例中对相应构造的解释。
功能模板,成员函数模板或类模板的成员函数或静态数据成员的专业化可以在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于翻译单元中具有实例化点的任何此类专业化,翻译单元的末尾也被视为实例化点。类模板的专门化在翻译单元中最多具有一个实例化点。任何模板的专业化可能在多个翻译单元中具有实例化点。如果根据一定义规则,两个不同的实例化点赋予模板专业化不同的含义,则程序格式错误,无需诊断。
我错了?或不幸的是这个程序是正确的。
答案 0 :(得分:5)
我希望以下内容会构成不良的NDR,但似乎不是:-(
您不能将程序已编译(并运行)的事实作为其格式不正确的证据,即NDR。就像您不能使用程序的看似有效的输出来证明它没有表现出未定义的行为一样。
也就是说,这里的相关规则是[temp.point]/8:
类模板的专门化在翻译单元中最多具有一个实例化点。任何模板的专业化可能在多个翻译单元中具有实例化点。如果根据一定义规则,两个不同的实例化点赋予模板专业化不同的含义,则程序格式错误,无需诊断。
我们只有一个实例化点is_complete<X>
:正好在第一个static_assert
之前。因此,这是“很好的”-可以说是令人困惑和糟糕的,但它的格式正确。
但是,如果我们将其拆分:
// a.cpp
struct X;
static_assert(!is_complete<X>::value);
// b.cpp
struct X { };
static_assert(is_complete<X>::value);
现在这是错误的形式,不需要诊断。
请注意,您不需要sizeof(T) != 0
。只需sizeof(T)
就可以了。您不能采用sizeof
的不完整类型,因此只需要检查sizeof(T)
是有效的表达式即可。