Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static assertion for a move constructor different from the copy constructor

Imagine that I have a class A that is cheap to move and expensive to copy. It could look like

class A {
  public: 
    [...]

  private:
    HeavyClass m;
};

For this class, I would like an static verification that the class (1) is move constructible and (2) does not simply use the copy constructor for move construction, independently of whether the move constructor was explicitly declared or not.

Is this possible?

As to why I would like this, consider the following example: At first, the class generates the move constructor automatically and behaves as desired. Then, someone changes the class and adds a destructor, which causes the move constructor not to be implicitly generated and the copy constructor to be used instead.

Therefore, a static_assert would be ideal, but it seems that none of is_move_constructible or is_trivially_move_constructible is helpful here.

Also, I know that it is possible to have A(A&&) = default; for all such classes but a solution with a static_assert would be cleaner and allow for doing the check outside of the class definition (f.i. in other projects relying on this class).

EDIT:
I do not want to forbid copy construction, I would just like to make sure that the move constructor is not using it...

like image 807
oLen Avatar asked Feb 08 '17 13:02

oLen


1 Answers

If you can change A to have an indirection, you may do the following:

template <bool>
struct MoveOnly {
    MoveOnly() = default;
    ~MoveOnly() = default;
    MoveOnly(const MoveOnly&) = delete;
    MoveOnly(MoveOnly&&) = default;
    MoveOnly& operator=(const MoveOnly&) = delete;
    MoveOnly& operator=(MoveOnly&&) = default;
};

template <> struct MoveOnly<false> {};

template <bool check = false>
class A_Impl : MoveOnly<check> {
public: 
    // ... as ~A_Impl() {}
    // ...
private:
    HeavyClass m;
};

using A = A_Impl<false>; // Normal case

// The check
static_assert(std::is_move_constructible<A_Impl<true>>::value, "");

Demo

like image 106
Jarod42 Avatar answered Nov 16 '22 01:11

Jarod42