Are these three default constructors equivalent in C++?

166 Views Asked by At

Consider the following code:

#include <type_traits>

template<typename T>
struct A1 {
    T t;

    // implicitly-declared default constructor
};

template<typename T>
struct A2 {
    T t;

    // explicitly-declared default constructor without noexcept
    A2() = default;
};

template<typename T>
struct A3 {
    T t;

    // explicitly-declared default constructor with noexcept
    A3() noexcept(std::is_nothrow_default_constructible<T>::value) = default;
};

Are these three default constructors equivalent in C++?

3

There are 3 best solutions below

0
Jeff Garrett On BEST ANSWER

None of these is equivalent to each other.

First, A1<T> is an aggregate whereas A2<T> and A3<T> are not. See godbolt. The definition of aggregate has varied across standards, and this is an aggregate (again) in C++20... so if you support older standards, A1<T> will have very different powers in each.

This has a strong effect on where and how these can be constructed. If one can construct a T, one can construct an A1<T> but not necessarily an A2<T> or A3<T>. See godbolt.

So A1<T> varies from the others in whether you can construct it at all.

A2<T> and A3<T> differ in whether the default constructor is noexcept. std::is_nothrow_default_constructible_v does not check only if a value is nothrow constructible but also destructible. Whereas the defaulted declaration without noexcept specification only checks constructors. See godbolt. (This is LWG 2116.)

8
user12002570 On

Are these three default constructors equivalent in C++?

Yes the default ctors are equivalent in the context of noexcept specification.

This can be seen from default ctor:

The implicitly-declared (or defaulted on its first declaration) default constructor has an exception specification as described in dynamic exception specification(until C++17) noexcept specification(since C++17).

So we move onto noexcept specification:

Every function in C++ is either non-throwing or potentially throwing:

  • potentially-throwing functions are:
    • functions declared without noexcept specifier except for
      • default constructors, copy constructors, move constructors that are implicitly-declared or defaulted on their first declaration unless
        • a constructor for a base or member that the implicit definition of the constructor would call is potentially-throwing (see below)
6
Sebastian Redl On

Two and three are equivalent; three is just error-prone and redundant.

The first one is equivalent in terms of constructor functionality. However, because it doesn't have any explicitly declared (even defaulted) constructor, the struct is an aggregate, which the other two aren't.