jotik jotik - 28 days ago 6
C++ Question

Determine whether a constructor of an abstract base class is noexcept?

In C++11 and later, how to determine whether a constructor of an abstract base class is

noexcept
? The following methods don't work:

#include <new>
#include <type_traits>
#include <utility>

struct Base { Base() noexcept; virtual int f() = 0; };

// static assertion fails, because !std::is_constructible<Base>::value:
static_assert(std::is_nothrow_constructible<Base>::value, "");

// static assertion fails, because !std::is_constructible<Base>::value:
static_assert(std::is_nothrow_default_constructible<Base>::value, "");

// invalid cast to abstract class type 'Base':
static_assert(noexcept(Base()), "");

// invalid new-expression of abstract class type 'Base'
static_assert(noexcept(new (std::declval<void *>()) Base()), "");

// cannot call constructor 'Base::Base' directly:
static_assert(noexcept(Base::Base()), "");

// invalid use of 'Base::Base':
static_assert(noexcept(std::declval<Base &>().Base()), "");


A simple use for this would be:

int g() noexcept;
struct Derived: Base {
template <typename ... Args>
Derived(Args && ... args)
noexcept(noexcept(Base(std::forward<Args>(args)...)))
: Base(std::forward<Args>(args)...)
, m_f(g())
{}

int f() override;

int m_f;
};


Any ideas about how to archieve this or whether it is possible at all without modifying the abstract base class?

PS: Any references to ISO C++ defect reports or work-in-progress is also welcome.

EDIT: As was pointed out twice, defaulting the
Derived
constructors with
= default
makes
noexcept
being inherited. But this does not solve the problem for the general case.

Answer

Based on skypjack's answer a better solution which does not require a signature change of the Derived constructor would be to define a mock subclass of Base as a private type member of Derived, and use the construction of that in the Derived constructor noexcept specification:

class Derived: Base {

private:

    struct MockDerived: Base {
        using Base::Base;

        // Override all pure virtual methods with dummy implementations:
        int f() override; // No definition required
    };

public:

    template <typename ... Args>
    Derived(Args && ... args)
            noexcept(noexcept(MockDerived(std::forward<Args>(args)...)))
        : Base(std::forward<Args>(args)...)
        , m_f(g())
    {}

    int f() override { return 42; } // Real implementation

    int m_f;

};
Comments