Reputation: 2843
Basically per the standard:
An inheriting constructor (12.9) and an implicitly declared special member function (Clause 12) have an exception-specification. If
f
is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idT
if and only ifT
is allowed by the exception-specification of a function directly invoked byf
’s implicit definition;f
allows all exceptions if any function it directly invokes allows all exceptions, andf
has the exception-specificationnoexcept(true)
if every function it directly invokes allows no exceptions.
Therefore the following code snipped shall have an implicit noexcept move constructor:
template<typename _Tp>
class Foo
{
public:
Foo() = default;
explicit Foo(const std::string& s, const std::function<bool(_Tp&)>& f) : stringField(s), funcField(f) {}
private:
const std::string stringField;
std::function<bool(_Tp&)> funcField;
};
but unfortunately, it does not:
int main()
{
std::cout << "std::string: " << std::is_nothrow_move_constructible_v<std::string> << std::endl;
std::cout << "std::function: " << std::is_nothrow_move_constructible_v<std::function<bool(std::string&)>> << std::endl;
std::cout << "string_t: " << std::is_nothrow_move_constructible_v<Foo<std::string>> << std::endl;
return 0;
}
prints
std::string: 1
std::function: 1
string_t: 0
using g++ 8.3.0 on Ubuntu 18.04 LTS
Is there something I am missing?
Upvotes: 3
Views: 188
Reputation: 238451
Is there something I am missing?
Yes. const
The member Foo::stringField
is not std::string
, it is const std::string
. const std::string
is not nothrow move constructible1, and therefore the implicit move constructor of Foo
is neither.
1 Const rvalue cannot bind to a non-const rvalue reference, so move constructor will not be used. Instead, copy constructor is used and copy constructor of std::string
is potentially throwing.
Upvotes: 7