c++classstandardsdefault-constructornoexcept

Are these three default constructors equivalent in C++?


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++?


Solution

  • 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.)