I encounter an issue while using the noexcept
specifier on derived classes, more precisely when the parent is an abstract class (has protected
constructors).
Hereafter is an example of the way I declare my classes.
- With a
public
constructor in the base class: Everything is ok. - Same code with
protected
and the derived class is no more "nothrow movable".
Do I miss something? Is std::is_nothrow_move_constructible
the correct traits to use in derived class declarations or should I use something else?
#include <cstdlib>
#include <iostream>
class BaseOk
{
public:
BaseOk ( BaseOk&& other ) noexcept {}
};
class BaseNok
{
protected:
BaseNok ( BaseNok&& other ) noexcept {}
};
class ChildOk : public BaseOk
{
public:
ChildOk ( ChildOk&& other ) noexcept ( std::is_nothrow_move_constructible < BaseOk >::value )
: BaseOk ( std::move ( other ) ) {}
};
class ChildNok : public BaseNok
{
public:
ChildNok ( ChildNok&& other ) noexcept ( std::is_nothrow_move_constructible < BaseNok >::value )
: BaseNok ( std::move ( other ) ) {}
};
int main ()
{
std::cout << std::boolalpha;
std::cout << "Is BaseOk move constructible? " << std::is_move_constructible < BaseOk >::value << '\n';
std::cout << "Is ChildOk move constructible? " << std::is_move_constructible < ChildOk >::value << '\n';
std::cout << '\n';
std::cout << "Is BaseOk nothrow move constructible? " << std::is_nothrow_move_constructible < BaseOk >::value << '\n';
std::cout << "Is ChildOk nothrow move constructible? " << std::is_nothrow_move_constructible < ChildOk >::value << '\n';
std::cout << '\n';
std::cout << "Is BaseNok move constructible? " << std::is_move_constructible < BaseNok >::value << '\n';
std::cout << "Is ChildNok move constructible? " << std::is_move_constructible < ChildNok >::value << '\n';
std::cout << '\n';
std::cout << "Is BaseNok nothrow move constructible? " << std::is_nothrow_move_constructible < BaseNok >::value << '\n';
std::cout << "Is ChildNok nothrow move constructible? " << std::is_nothrow_move_constructible < ChildNok >::value << '\n';
std::cout << std::endl;
return EXIT_SUCCESS;
}
Output:
Is BaseOk move constructible? true
Is ChildOk move constructible? true
Is BaseOk nothrow move constructible? true
Is ChildOk nothrow move constructible? true
Is BaseNok move constructible? false
Is ChildNok move constructible? true
Is BaseNok nothrow move constructible? false
Is ChildNok nothrow move constructible? false
___ EDIT ____________________________________________________________
After searching around for a while, and regarding to the andswer of Oleg Bogdanov, it unfortunately seems not possible to combine protected
constructors with usage of noexcept ( is_nothrow_... )
.
I was writting abstract classes and declared constructors protected
for documentation purposes only. Now, constructors are back to public
but I'm facing another problem:
As an abstract class cannot be instanciated, std::is_nothrow_move_constructible<BaseClass>
returns false
and all derived classes can never be tagged as not throwing exceptions even if they are not.
See example below:
#include <cstdlib>
#include <iostream>
class Foo
{
public:
Foo ( Foo&& other ) noexcept {}
virtual ~Foo () = 0; // Removing '= 0' makes both outputs print 'true'.
};
Foo::~Foo () {}
class Bar : public Foo
{
public:
Bar ( Bar&& other ) noexcept ( std::is_nothrow_move_constructible < Foo >::value )
: Foo ( std::move ( other ) ) {}
};
int main ()
{
std::cout << std::boolalpha;
std::cout << "Foo: " << std::is_nothrow_move_constructible < Foo >::value << '\n';
std::cout << "Bar: " << std::is_nothrow_move_constructible < Bar >::value << '\n';
return EXIT_SUCCESS;
}
Output:
Foo: false
Bar: false