c++sfinaeincomplete-type

How to check that a C++ class is incomplete (only declared)?


I would like to write a C++ function that will check that its template parameter class is incomplete, so only class declaration is available but not full definition with all class members.

My function incomplete() looks as follows together with some demo program:

#include <type_traits>
#include <iostream>

template <typename T, typename V = void> constexpr bool is_incomplete = true;
template <typename T> constexpr bool is_incomplete<T, std::enable_if_t<sizeof(T)>> = false;
template <typename T> constexpr bool incomplete() { return is_incomplete<T>; }

struct A;
void print() { std::cout << incomplete<A>(); }
struct A {}; //this line affects GCC

int main()
{
    print();
}

It works well in Clang printing 1, but in GCC the program prints 0 despite the fact that A class is incomplete in function print. https://gcc.godbolt.org/z/qWW3hqbEv

Is GCC wrong here or there is a fault in my program?


Solution

  • Which compiler is correct is currently undecided. It's CWG Issue 1845.

    The current wording of 13.8.4.1 [temp.point] does not define the point of instantiation of a variable template specialization. Presumably replacing the references to “static data member of a class template” with “variable template” in paragraphs 1 and 8 would be sufficient.

    Given that issue is still in drafting stage (and no normative wording exists yet it the latest available draft), it remains unresolved. It isn't clear if a variable template can have multiple points of instantiation or not (though the direction the issue reporter suggests is clear).

    For entities with multiple points of instantiation, the end of the translation unit is one as well. Also, if two points disagree on the definition of template, it's an ODR violation, plain and simple. GCC seems to provide two points, so you see the result of that. And I tend to agree with GCC here. A variable template is in many ways a shorthand for a static data member of a class template, and static data members do have multiple points of instantiation.

    Either way, this is playing with the risk of nasal demons. Checking a type for complete-ness is not really possible reliably if that state can change in a TU (and possibly even if it can change in the entire program).