4

I just stumbled upon the following differences between GCC and Clang concerning an explicitly defaulted constexpr ctor and some inheritance...

template <typename T>
struct A {
  constexpr A() = default;
  T v;
};

struct B : A<int> {
  constexpr B() = default;
};

GCC immediately rejects the code while Clang allows to instantiate non-constexpr versions of both types. My guess is that Clang is probably correct, but I'm not 100% certain...

1
  • 3
    initialize A::v and gcc will be happy. Commented May 10, 2019 at 21:58

1 Answer 1

6

The problem boils down to: is a constexpr constructor that default-initializes some non-static data member of builtin type valid, if it is not used?


tl;dr:

  • For a non-template constructor, no, it is invalid to leave any non-static data members uninitialized.

  • For a template constructor, yes, it is valid to have some (but not all, no diagnostic required) instantiated template specializations for which the instantiated constructor does not meet the requirements of a constexpr constructor.

In this case, GCC is right, whereas Clang is wrong.


GCC gives the following error message which is very informative:

prog.cc:8:13: error: explicitly defaulted function 'constexpr B::B()' cannot be declared as 'constexpr' because the implicit declaration is not 'constexpr':
    8 |   constexpr B() = default;
      |             ^
prog.cc:3:13: note: defaulted constructor calls non-'constexpr' 'A<T>::A() [with T = int]'
    3 |   constexpr A() = default;
      |             ^
prog.cc:3:13: note: 'A<T>::A() [with T = int]' is not usable as a 'constexpr' function because:
prog.cc:4:5: note: defaulted default constructor does not initialize 'int A<int>::v'
    4 |   T v;
      |     ^

live demo

Note that the error is raised on the constructor of B, instead of that of A, whose constructor is merely "not usable as a constexpr function because [the] defaulted default constructor does not initialize int A<int>::v."


Per [dcl.constexpr]/4:

The definition of a constexpr constructor shall satisfy the following requirements:

  • the class shall not have any virtual base classes;
  • each of the parameter types shall be a literal type.

In addition, either its function-body shall be = delete, or it shall satisfy the following requirements:

  • [...]
  • every non-variant non-static data member and base class subobject shall be initialized ([class.base.init]);
  • [...]

Here, v is of type int, and is not initialized. Therefore, it seems that the constructor of A cannot be declared constexpr.

However, [dcl.constructor]/6 says:

If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is still a constexpr function or constexpr constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required.

Therefore, the constructor of A that is declared constexpr is actually valid, even when instantiated for T = int!


The problem is the constructor of B. B is an ordinary class (as opposed to a class template), and for its constructor to be (merely) declared constexpr, A<int> must have a constexpr constructor, which is not the case.

Therefore, this code should be rejected, as GCC does.


(Note that both compilers reject initialization of such a type, for example:

A a{};
B b{};

The above code is rejected by both compilers.)

As mentioned in a comment, initialize A::v and GCC (and the standard) will be happy.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.