Consider following code:
#include <type_traits>
struct T {};
static_assert(std::is_trivially_destructible< T >{});
static_assert(std::is_trivially_default_constructible< T >{});
struct N { ~N() { ; } };
static_assert(!std::is_trivially_destructible< N >{});
static_assert(!std::is_trivially_default_constructible< N >{});
It compiles fine using clang 3.7.0
: live example. But summarizing the Standard:
The default constructor for class T is trivial (i.e. performs no action) if all of the following is true:
- The constructor is not user-provided (i.e., is implicitly-defined or defaulted)
- T has no virtual member functions
- T has no virtual base classes
- T has no non-static members with default initializers. (since C++11)
- Every direct base of T has a trivial default constructor
- Every non-static member of class type has a trivial default constructor
As I can see there is no dependence on triviality of the destructor.
I missed something? Is it clang
bug?
I found a workaround: is static_assert(__has_trivial_constructor( N ));
built-in type trait. There is support in clang
, gcc
and MSVC
.
For is_noexcept_constructible
family of type traits there is workaround too.
A class has a non-trivial destructor if it either has an explicitly defined destructor, or if it has a member object or a base class that has a non-trivial destructor.
If you define a constructor yourself, it is considered non-trivial, even if it doesn't do anything, so a trivial constructor must be implicitly defined by the compiler.
This issue is covered in LWG issue 2116: std::swap noexcept(what?), we can see this from the cppreference section for std::is_trivially_default_constructible:
In many implementations, is_nothrow_default_constructible also checks if the destructor throws because it is effectively noexept(T()): GCC bug 51452 LWG issue 2116
which deceptively only talks about is_nothrow_default_constructible
but if we read the issue in detail we see it also applies here as well.
Perhaps is is easier if we follow the gcc bug report: [DR 2116] has_nothrow_.*constructor bugs referenced first which says:
The traits that detect nothrow constructibility are buggy because they are influenced by whether the object has a nothrow dtor; destruction is invoked at the end of evaluation of the full expression in the noexcept( ... ) operator. They all use the pattern of constructing a temporary inside noexcept, whereas they should be using placement new
this explicitly says what is only really alluded to in the LWG issue which eventually says:
is_nothrow_constructible is defined in terms of is_constructible, which is defined by looking at a hypothetical variable and asking whether the variable definition is known not to throw exceptions. The issue claims that this also examines the type's destructor, given the context, and thus will return false if the destructor can potentially throw. At least one implementation (Howard's) does return false if the constructor is noexcept(true) and the destructor is noexcept(false). So that's not a strained interpretation. The issue is asking for this to be defined in terms of placement new, instead of in terms of a temporary object, to make it clearer that is_nothrow_constructible looks at the noexcept status of only the constructor, and not the destructor.
which also effects std::is_trivially_default_constructible
which relies on std::is_trivially_constructible which does the same as is_constructible
but has the further restriction that:
but the variable definition does not call any operation that is not trivial
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With