Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Class template instantiation with incomplete types

Is the following ill-formed program? If so, what the issue with giving diagnostic here?

template <typename T> struct A { int a{sizeof(T)}; };
int main() { sizeof(A<void>); }

Clang generates the following specialization for that code (clang++ -std=c++20 -Xclang -ast-print -fsyntax-only main.cpp):

template <typename T> struct A {
    int a {sizeof(T)};
};
template<> struct A<void> {
    int a;
};
int main() {
    sizeof(A<void>);
}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

For class templates, the definitions inside will only be instantiated when used.
In the example:

template <typename T>
struct A {
    int a{sizeof(T)};
};

An application of sizeof to A<void> only requires an instantiation of A and knowing what types the data members have. The expression sizeof(T) is type-dependent on T and not necessary, so neither GCC nor Clang will instantiate it here. This is allowed:

The implicit instantiation of a class template specialization causes

  • the implicit instantiation of […]

The implicit instantiation of a class template specialization does not cause the implicit instantiation of default arguments or noexcept-specifiers of the class member functions.

[temp.inst]/3

Initializers of non-static data members are not listed in this paragraph, so we are safe so far. The member will actually be instantiated when:

[…] the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program;

[temp.inst]/4

The definition of a and its initializers don’t have to be instantiated for sizeof(A<void>), because it is not required to exist and doesn’t affect the semantics of the program.

However, if you created a variable with type A<void>, then the compiler would need to instantiate the default member initializer in A, making the program ill-formed:

int main() {
    sizeof(A<void>); // OK up to this point
    A<void> a;       // ill-formed (GCC issues warning, Clang issues error)
}

Note on -Xclang -ast-print -fsyntax-only

template<> struct A<void> {
   int a;
};

Note that what you are seeing is only a representation of what clang has instantiated so far. The generated syntax tree doesn’t contain the default member initializer of a at all. This is not a representation of what A<void> is once fully instantiated (including all members), only what what clang knows so far.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading