根据实例化点期望不同的类型 [英] Expecting different types depending of point of 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
注意:假定sizeof(T) != 0
对完整性特征有效(因为没有类型可以具有sizeof(T) == 0
,所以使用其他常量将强制为这些特征找到一个更好的名称:))>
这是 http://eel.is/c++draft/temp.res #8.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)
是有效的表达式即可.
I expect the following to be ill formed NDR, but it seems not :-(
#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
Note: Assuming sizeof(T) != 0
is valid for completeness traits (as no types can have sizeof(T) == 0
, using other constant would force to find a better name for the traits :-) )
It is a variation of the code from Is a specialization implicitly instantiated if it has already been implicitly instantiated?, where the program has been declared ill-formed program, No Diagnostic Required (NDR), as the method is_complete_helper<X>::test<X>
has 2 different meanings depending of the points of instantiation.
References which seems near to make the program ill formed, but doesn't as I understand:
the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template.
A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
I'm wrong ? or unfortunately this program is correct.
I expect the following to be ill formed NDR, but it seems not :-(
You cannot use the fact that a program compiles (and runs) as evidence that it is not ill-formed, NDR. In the same way that you cannot use seemingly valid output of a program to demonstrate that it doesn't exhibit undefined behavior.
That said, the relevant rule here is [temp.point]/8:
A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.
We just have one point of instantiation of is_complete<X>
: which is right before the first static_assert
. So, this is "fine" - it's arguably confusing and bad, but it's well-formed.
But, however, if we split this up:
// a.cpp
struct X;
static_assert(!is_complete<X>::value);
// b.cpp
struct X { };
static_assert(is_complete<X>::value);
Now this is ill-formed, no diagnostic required.
Note, you don't need sizeof(T) != 0
. Just sizeof(T)
is fine. You cannot take sizeof
of an incomplete type, so you simply need to check that sizeof(T)
is a valid expression.
这篇关于根据实例化点期望不同的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!