constexpr移动构造函数是否有意义

Does a constexpr move constructor ever make sense?

本文关键字:有意义 是否 构造函数 移动 constexpr      更新时间:2023-10-16

拥有constexpr移动构造函数是否有意义?

例如,请考虑以下内容:

#include <array>
class C
{
public:
    constexpr C(std::array<int, 3> ar) : m_ar{ar} {}
    constexpr C(C&& other) : m_ar{std::move(other.m_ar)} { }
private:
    std::array<int, 3> m_ar;
};
int main()
{
    constexpr C c1 {{{1, 2, 3}}};
    constexpr C c2{std::move(c1)};
    return 0;
}

这并不是编译,因为尽管在c1上调用std::move,但编译器可以推论它需要使用(隐式删除)复制构造函数,而不是移动构造函数。我不确定为什么。

但是,如果我从c1删除constexpr,那么constexpr移动构造函数将变得无法使用。

有什么办法可以使它起作用?还是constexpr移动构造函数的一个不好的例子,但是有一个很好的例子?或者,拥有constexpr移动构造函数总是错误的?

原则上,可以将移动构造函数与非const对象一起使用,其寿命在评估常数表达式期间开始:

// C++14
constexpr int f() {
    C a(/* ... */);
    C b = std::move(a);
    return 0;
}
constexpr int i = f();

可以在C 11中完成类似的事情,例如

constexpr C foo(C&& c) { 
    return std::move(c); 
}
constexpr int f() { 
    return foo(C()), 0; 
}

也就

这不会编译,因为尽管在c1上调用std::move,但编译器仍需要使用(隐式删除)复制构造函数

进行编译器。

c1是类型C const。当您move()时,这确实是rvalue参考的铸件,因此您将获得C const&&。请注意,它仍然是const。当我们执行过载分辨率时,有三个构造函数:

C(std::array<int, 3> ); // not viable
C(C&& );                // not viable
C(C const& ) = delete;  // viable!

C const&&无法与C&&结合,因为C const&无法绑定到C&。我们只剩下复制构造函数,该构造函数被隐式删除。


具有constexpr移动构造函数可能是有道理的 - 但是您要从"移动"的对象真的不能从中移动,因为它大概是const。您可以添加const移动构造函数:

constexpr C(C const&& other) : m_ar(other.m_ar) { }

这是一个荣耀的复制构造函数,但允许您想要的语法。也可以允许复制。