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

时间:2017-02-20 15:27:43

标签: c++ c++11 constexpr move-constructor

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

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

但是,如果我从constexpr中移除c1,则constexpr移动构造函数会使其无法使用。

有什么方法可以让它发挥作用吗?或者这是一个constexpr移动构造函数的坏例子,但有很好的例子吗?或者,拥有constexpr移动构造函数是否总是错误的?

2 个答案:

答案 0 :(得分:2)

  

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

c1的类型为C const。当你move()它时,这实际上是对右值引用的强制转换,因此你得到一个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) { }

这是一个美化的复制构造函数,但它允许您想要的语法。也许只是允许复制。

答案 1 :(得分:2)

原则上,移动构造函数可以与非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; 
}

也就是说,因为在常量表达式中使用的所有东西都需要被轻易破坏,所以移动构造函数的用处相当有限。