根据实例化的不同,期望不同的类型

Jar*_*d42 2 c++ templates language-lawyer template-instantiation

我希望下面的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
Run Code Online (Sandbox Code Playgroud)

演示

注意:假设sizeof(T) != 0对完整性特征有效(因为没有类型可以使用sizeof(T) == 0,使用其他常量会强制为特征找到更好的名称:-))

如果已经隐式实例化了隐式实例化的特殊化,它是代码的变体吗?,程序已被宣布为格式错误的程序,无需诊断(NDR),因为该方法 is_complete_helper<X>::test<X> 具有2种不同的含义,具体取决于实例化点.

似乎附近的参考文件使程序形成不良,但并不像我所理解的那样:

在假设实例中对这种构造的解释不同于在模板的任何实际实例化中对相应构造的解释.

函数模板,成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元内具有多个实例化点,并且除了上述实例化的点之外,对于任何这样的实例化.在翻译单元内具有实例化点的专门化,翻译单元的末尾也被认为是实例化的点.类模板的专门化在翻译单元中最多只有一个实例化点.任何模板的特化可以在多个翻译单元中具有实例化点.如果两个不同的实例化点根据单定义规则给出模板特化的不同含义,则程序形成错误,不需要诊断.

我错了 ?或者不幸的是这个程序是正确的.

Bar*_*rry 6

我希望下面的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);
Run Code Online (Sandbox Code Playgroud)

现在这是不正确的,不需要诊断.


注意,你不需要sizeof(T) != 0.只要sizeof(T)是好的.你不能采用sizeof不完整的类型,所以你只需要检查它sizeof(T)是一个有效的表达式.