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



我希望以下内容是格式错误的 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,使用其他常量将强制为特征找到更好的名称:-(

它是代码的变体,来自 如果已经隐式实例化,则是否隐式实例化专用化?,其中程序已声明为格式错误的程序,无需诊断 (NDR(,因为方法is_complete_helper<X>::test<X>具有 2 种不同的含义,具体取决于实例化点。

似乎接近使程序格式不正确的参考文献,但据我所知:

  • http://eel.is/c++draft/temp.res#8.5

假设实例化中对此类构造的解释不同于在模板的任何实际实例化中对相应构造的解释。

  • http://eel.is/c++draft/temp.res#temp.point-8
函数模板、成员函数模板或

类模板的成员函数或静态数据成员的专用化在翻译单元中可能具有多个实例化点,除了上述实例化点之外,对于在翻译单元中具有实例化点的任何此类专用化, 翻译单元的结尾也被视为实例化点。类模板的专用化在翻译单元中最多有一个实例化点。任何模板的专用化都可以在多个翻译单元中具有实例化点。如果两个不同的实例化点根据一个定义规则赋予模板专用化不同的含义,则程序格式不正确,无需诊断。

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

我希望以下内容是格式错误的 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)是否为有效表达式。

相关内容

最新更新