30
votes

In C++11 if both copy and move assignment are available, the compiler automatically chooses copy assignment if the argument is lvalue and move assignment if it is rvalue. Using std::move it is possible to explicitely select the move assignment for lvalue. But how is it possible to explicitely select the copy assignment for rvalue?

Code example:

#include <iostream>

class testClass
{
public:
    testClass &operator=(const int &other) {
        std::cout << "Copy assignment chosen." << std::endl;
        return *this;
    }

    testClass &operator=(int &&other) {
        std::cout << "Move assignment chosen." << std::endl;
        return *this;
    }   
};  

int main(int argc, char *argv[])
{
    int a = 4;
    testClass test;

    test = a; // Selects copy assignment
    test = 3; // Selects move assignment

    test = std::move(a); // Selects move assignment
//  test = std::copy(3); // <--- This does not work

    return 0;
}
2
You can static_cast to const int& : test = static_cast<const int&>(3); - rahnema1
@rahnema1 Comment is not for answering, you know... - user2486888
@NickyC : Sometimes one only wants to bother writing one sentence, and one sentence is rarely a good answer. ;-] - ildjarn
If you have both operators, the functionality is written to handle the parameter correct. For that reason it looks not very useful to "manually" select a different operator as the "natural right" one. Like with std::move, it will result in the objects "invalid state". If that is expected, fine! But if handling an rvalue as lvalue? - Klaus
I'm curious as to the motivation for doing this - gyre

2 Answers

19
votes

One possible way is to write your own copy to bind the object to an lvalue reference:

template <class T>
constexpr T& copy(T&& t) noexcept
{
    return t;
}

And you can test it this way:

test = copy(a);
test = copy(3);
test = copy(std::move(a));

You may put this function in your own namespace to keep things clean. You may also choose a better name for it.


To address fear of lifetime issue, here is some considerations:

  • This copy function takes a reference and returns the same reference immediately. It implies that the caller is responsible for controlling the lifetime.
  • Lifetime of a temporary object persists until the end of the statement. This makes the object persists long enough to be passed into the left hand side of =.
8
votes

You can static_cast to const int&:

test = static_cast<const int&>(3);