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++?
None of these is equivalent to each other.
First,
A1<T>is an aggregate whereasA2<T>andA3<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 anA1<T>but not necessarily anA2<T>orA3<T>. See godbolt.So
A1<T>varies from the others in whether you can construct it at all.A2<T>andA3<T>differ in whether the default constructor isnoexcept.std::is_nothrow_default_constructible_vdoes 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.)