Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't the noexcept specifier scoped within the declared method?

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?

like image 277
monkey0506 Avatar asked Mar 07 '16 23:03

monkey0506


Video Answer


1 Answers

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.

like image 109
Kurt Stutsman Avatar answered Sep 19 '22 12:09

Kurt Stutsman