【问题标题】:Incomplete type works with gcc but not with clang and msvcIncomplete type works with gcc but not with clang and msvc
【发布时间】:2022-12-01 23:41:56
【问题描述】:

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?

【问题讨论】:

  • Interestingly, as soon as you odr-use t, gcc also rejects the code. This might be an indication as to why gcc accepts it in the first place.
  • Looks like ill-formed.
  • You need to "complete" the type eventually. Else the program is ill-formed.

标签: c++ language-lawyer c++20


【解决方案1】:

The program isill-formedandgcc is wrong in accepting the codebecause even though thedefinitionof the static data member is not instantiated(because it is not odr-used), it'sdeclarationwill still be instantiated due to theimplicit instantiationof C&lt;incomplete&gt; as per temp.inst#3. More importantly, if adeclarationuses 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:

  • theimplicit instantiation of the declarations, but not of the definitions, of thenon-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&lt;incomplete&gt; will cause the implicit instantiation of thedeclarationof the static data member.

Further from static data member documentation:

However, if the declaration uses constexpr or inline (since C++17) specifier, the membermust 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 isill-formed.


Here is the gcc bug report:

GCC accepts invalid program involving constexpr static data member of class template

【讨论】:

  • Yes, I think [temp.inst] is key to deciding whether [basic.def] even applies. +1
  • @bitmask Thanks, here is the gcc bug report.
【解决方案2】:

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.

【讨论】:

    猜你喜欢
    • 2015-09-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 2019-04-29
    相关资源
    最近更新 更多