Trying to design some exception-free classes, I have an inheritance structure similar to this, but I have found the noexcept specifier to be of little to no help when working with member functions as the specifier is not scoped as being within the function.
class Base
{
protected:
Base() noexcept {}
};
class Derived : public Base
{
public:
// error: 'Base::Base()' is protected
Derived() noexcept(noexcept(Base{})) : Base{} {}
// error: 'foo' was not declared in this scope
Derived(int) noexcept(noexcept(foo())) {}
// error: invalid use of 'this' at top level
Derived(float) noexcept(noexcept(this->foo())) {}
void foo() noexcept {}
};
Demo
Is this perhaps something that is being improved in C++17? Trying to search for this has yielded no relevant results. For now I've resigned to some very ugly (and possibly incorrect) attempts such as noexcept(noexcept(static_cast<Derived*>(nullptr)->foo())), but this doesn't assist in the case of the base class constructor, which is protected.
Is it even currently possible to declare a noexcept specifier which references a protected base class method like this? noexcept(auto) might be relevant, but of course isn't possible yet. Have I overlooked anything else that would allow me to include this specifier, or do I simply have to omit it in that case?
You can work around it by using an expression where the Base constructor is in scope like this:
struct test_base : public Base {};
Derived() noexcept(noexcept(test_base())) : Base() {}
I believe the reason you cannot use Base() directly is related to this question.
The way protected access specifier works, it allows the derived class B to access the contents of an object of base class A only when that object of class A is a subobject of class B. That means that the only thing you can do in your code is to access the contents of A through B: you can access the members of A through a pointer of type B * (or a reference of type B &). But you cannot access the same members through a pointer of type A * (or reference A &).
It's the same as if you had a member function like this:
void badfunc()
{
B b;
}
You're trying to use Base's constructor directly instead of going through Derived. When you initialize the base in the constructor initialization list, that is a special context that allows you to call the constructor because you're doing it as part of initializing Derived.
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