如果可能,隐式移动构造函数应为 noexcept

Implicit move constructor shall be noexcept if possible

基本符合标准:

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-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.

因此,以下截取的代码应具有隐式 noexcept 移动构造函数:

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;
};

但不幸的是,它没有:

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;
}

打印

std::string: 1  
std::function: 1  
string_t: 0

在 Ubuntu 18.04 LTS

上使用 g++ 8.3.0

有什么我遗漏的吗?

Is there something I am missing?

是的。 const

成员Foo::stringField不是std::string,而是const std::stringconst std::string 不是可构造的 1,因此 Foo 的隐式移动构造函数也不是。

1 Const 右值不能绑定到非const 右值引用,因此不会使用移动构造函数。相反,使用复制构造函数并且 std::string 的复制构造函数可能会抛出。