Search code examples
c++c++11type-traitsexception-specification

How to detect if a contructor is noexcept with a throwing destructor


The following code will fail to compile on most compilers:

#include <type_traits>

class Foo
{
    public:
    Foo() noexcept {}
    ~Foo() noexcept(false) {}
};

static_assert(std::is_nothrow_default_constructible_v<Foo>);

CppReference also states that this is common in compiler implementations, but provides no alternative. How can I test if a constructor is noexcept without the destructor influencing the result?


Solution

  • As mentioned in LWG issue 2116, linked from the cppreference page you linked, this is not a bug, but intended behavior.

    As also mentioned in that issue, one can use the non-throwing placement-new, which only constructs, but doesn't destruct an object, to test the exception specification of only the constructor:

    static_assert(noexcept(::new(std::nothrow) Foo()));
    

    This requires including <new> for std::nothrow.

    Here is a rough implementation of the trait:

    template<class T, class = void>
    struct is_nothrow_default_constructible
    : std::bool_constant<false> { };
    
    template<class T>
    struct is_nothrow_default_constructible<T,
        std::enable_if_t<noexcept(::new(std::nothrow) T())>>
    : std::bool_constant<true> { };