2

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

Demo

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.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I believe a combination of [this](https://stackoverflow.com/a/8452846/1708801) and this [this](https://stackoverflow.com/q/1625105/1708801) covers your question – Shafik Yaghmour Sep 10 '18 at 20:51

1 Answers1

7

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Right. I was confused for a moment :) – Rakete1111 Sep 10 '18 at 20:58
  • My *"it seems not"* was mostly due to the discussion from the linked question, and indeed compiler cannot be used for NDR proof ;-) . Sad that the code is correct :-(, especially when small "innocent" variation make it ill formed (as using explicitly a static data member `value` instead of inheritance of `bool_constant` for example). – Jarod42 Sep 10 '18 at 21:22