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.
A naive but working example would be to introduce a non-virtual base class and export its constructor by means of the using
directive. Here is an example:
#include<utility>
struct BaseBase {
BaseBase() noexcept { }
};
struct Base: public BaseBase {
using BaseBase::BaseBase;
virtual int f() = 0;
};
struct Derived: public Base {
template <typename ... Args>
Derived(Args && ... args)
noexcept(noexcept(BaseBase(std::forward<Args>(args)...)))
: Base(std::forward<Args>(args)...)
{ }
int f() override { }
};
int main() {
Derived d;
d.f();
}
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;
};
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