How to create a default constructor outside the noexcept class?

I know that a constructor marked as =default will "try" to be noexcept when possible. However, if I define it outside the class, this is no longer noexcept , as you can see from this code:

 #include <iostream> #include <utility> #include <type_traits> struct Bar { Bar() = default; Bar(Bar&&) = default; // noexcept }; struct Foo { Foo() = default; Foo(Foo&&); }; // moving the definition outside makes it noexcept(false) Foo::Foo(Foo&&) = default; // not noexcept anymore int main() { Foo foo; Bar bar; std::cout << std::boolalpha; // checks std::cout << std::is_nothrow_move_constructible<Bar>::value << std::endl; std::cout << std::is_nothrow_move_constructible<Foo>::value << std::endl; } 

How can I define such a constructor =default outside the class and make it noexcept ? And why is there such a constructor noexcept(false) if it is defined outside the class? This issue occurs when implementing PIMPL through smart pointers.

+6
source share
2 answers

The rules governing the exception specification for your two examples are discussed in section 8.4.2 / 2 [dcl.fct.def.default]

... If the function is clearly defaulted in the first declaration,
- it is implicitly considered constexpr if the implied declaration will be,
- it is implicitly considered to have the same exception specification as if it were implicitly declared (15.4) and
โ€”...

Bar move constructor noexcept(true) , because in ยง15.4 / 14 [except.spec]

An implicitly declared special member function (clause 12) must have an exception specification. If f is an implicitly declared default constructor, copy constructor, constructor move constructor , destructor, copy assignment operator or redirection operator, its implicit exception specification indicates the type -id T if and only if T allowed by the exception specification for the function directly called f implicit definition; f allows all exceptions if any function that it calls directly allows all exceptions, and f does not allow exceptions if every function it calls does not allow exceptions .

The rules in ยง8.4.2 / 2 do not apply to special member functions that were clearly defaulted after the initial declaration, with the exception of destructors which are special in ยง12.4 / 3, which should be noexcept(true) if you do not declare it noexcept(false) or destructors of one of the data elements or base classes may throw.

Thus, if you do not specify Foo(Foo&&) as noexcept(true) , it is assumed that it is noexcept(false) .

The reason why you need to add the noexcept specification of both the declaration and the more explicit default declaration is contained in ยง15.4

3 Two exception specifications are compatible if:
- both of them do not drop (see below), regardless of their shape,
โ€”...
4 If any function declaration has an exception specification that is not a noexcept specification that allows all exceptions, all declarations, including the definition and any explicit specialization, must have a compatible exception specification ....

+2
source

Now I realized that I can do this, it still hasnโ€™t crossed my mind:

 struct Foo { Foo() = default; Foo(Foo&&) noexcept; }; Foo::Foo(Foo&&) noexcept = default; // now it is noexcept 

Another second question. Why is it noexcept(false) by default? applies.

+4
source

Source: https://habr.com/ru/post/985888/


All Articles