Does constexpr move constructor make sense?

Does it make sense to have a constexpr move constexpr ?

For example, consider the following:

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

This does not compile because, despite calling std::move on c1 , the compiler infers that it needs to use the constructor (implicitly deleted), and not the move constructor. I'm not sure why.

But if I remove constexpr from c1 , then it will become unsuitable for the constexpr move constexpr .

Is there any way to make this work? Or this is a bad example for a constexpr displacement constexpr , but are there any good examples? Or is it just always wrong to have a constexpr move constexpr ?

+5
source share
2 answers

In principle, a move constructor can be used with an object not const , whose lifetime began when evaluating a constant expression:

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

Similar things can be done in C ++ 11, for example

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

However, since everything used in constant expression must be trivially destructible, the usefulness of the move constructor is quite limited.

+2
source

This does not compile because, despite calling std::move on c1 , the compiler infers that it needs to use the (implicitly deleted) copy constructor

c1 is of type C const . When you move() , this is a really great rvalue reference, so you get C const&& . Note that it is still const . When we do overload resolution, there are three constructors:

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

C const&& cannot bind to C&& for the same reason that C const& cannot bind to C& . All that remains for us is the copy constructor, which is implicitly deleted.


Having a constexpr move constructor may make sense - but the object you're moving from cannot be moved because it is supposedly const . You can add a const constructor:

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

This is an illustrious copy constructor, but it allows you syntax. Maybe just enable copying.

+2
source

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


All Articles