I have recently learnt about incomplete types and that under certain conditions they can be used as template arguments. In particular, like void
, struct incomplete;
are both incomplete types. Then I wrote the following program that works with gcc but not with msvc and clang. Live demo
struct incomplete;
template<typename T> struct C
{
static constexpr T t{};
};
template<class T>
struct myClass {
C<T> new_t() { return {}; }
};
int main() {
myClass<incomplete> d;
d.new_t();
}
As we can see the above program compiles with gcc but not with msvc and clang. So I want to know which is the correct technical behavior.
Clang says:
<source>:4:24: error: constexpr variable cannot have non-literal type 'const incomplete'
static constexpr T t{};
while msvc says:
<source>(4): error C2027: use of undefined type 'incomplete'
<source>(1): note: see declaration of 'incomplete'
while GCC accepts the code with both c 17 as well as c 20.
Which compiler is correct here?
CodePudding user response:
The program is ill-formed and gcc is wrong in accepting the code because even though the definition of the static data member is not instantiated(because it is not odr-used), it's declaration will still be instantiated due to the implicit instantiation of C<incomplete>
as per temp.inst#3. More importantly, if a declaration uses constexpr
or inline
(since C 17) specifier, the member must be declared to have complete type.
From temp.inst#3:
The implicit instantiation of a class template specialization causes:
- the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and
(emphasis mine)
This means that the implicit instantiation C<incomplete>
will cause the implicit instantiation of the declaration of the static data member.
Further from static data member documentation:
However, if the declaration uses
constexpr
orinline
(since C 17) specifier, the member must be declared to have complete type.
(emphasis mine)
This means that since the implicitly instantiated declaration, declares a member of an incomplete type, the program is ill-formed.
Here is the gcc bug report:
GCC accepts invalid program involving constexpr static data member of class template
CodePudding user response:
According to [basic.def] 5. this is ill formed:
In the definition of an object, the type of that object shall not be an incomplete type ([basic.types.general]), an abstract class type ([class.abstract]), or a (possibly multi-dimensional) array thereof.
This does not seem to make any allowances for non-odr-used members of class templates.