c++language-lawyerc++20

When does a type become complete?


Should the following program be rejected? Clang seems to accept it.

template<typename T>
concept c = requires { T::n; };
struct z;
constexpr bool b(auto...) { return c<z>; }
struct z { int n; };
static_assert(not b()); // clang ok, gcc nope, msvc nope

By the time b() is evaluated, template b has been implicitly stamped out, and type z is then complete. However, the expression c<z> within b doesn't depend on any of b's template parameters. So, I guess the question boils down to whether c<z> should be resolved when template b is defined or when it is being instantiated.

Demo


Solution

  • This is IFNDR per [temp.res.general]/6.5 because nothing in c<z> is dependent, but its meaning in the specialization differs at the point-of-definition from the point-of-instantiation. The notes below the reference also give non-dependent use of an incomplete type as an example.


    Also, while that is not exactly your question: Writing a type trait or concept to check for type completeness or that depends on type completeness doesn't really work. If anywhere in the program (including other translation units) the result differs for a given type, for example because the type has been completed between two checks, then the program will be IFNDR. That's why there is no such trait/concept in the standard library and why all standard library traits/concepts have a precondition for the type to be complete.