Search code examples
c++c++11copy-constructormove-semanticsgeneric-programming

C++11: shortest way to explicitly copy a value to use as an rvalue reference


I have a function

class A { <has copy and move constructors > };

void f(A &&a) { ... }

I want to call the function f with a variable x, but I want to run f on a copy of x, not x itself. Why can't I do something like this?

f(copy(x));

But instead must do

f(A(x));

Is there anything similar to the copy function I describe above?

Note: please don't tell me to add an overload f that does the copying, I want something that doesn't require an overload and is explicit (i.e. copy makes it clear to the reader that copying is done here)


Solution

  • template<class T>
    std::remove_cv_t<T> copy(T& t) {
      return t;
    }
    template<class T>
    void copy(T&&)=delete; // block rvalue copy
    template<class T, size_t N>
    void copy(T(&)[N]) = delete; // we can implement this if we want: see below
    

    will copy any lvalue. On rvalues and non-copyable types (like arrays) it will fail to match or compile.

    template<class T>
    std::decay_t<T> copy_even_if_rvalue(T&& t) {
      return std::forward<T>(t);
    }
    namespace details {
      template<class T, size_t N, size_t...Is>
      std::array<T, N> copy_even_if_rvalue(T(&arr)[N], std::index_sequence<Is...>)
      {
        return {{arr[Is]...}};
      }
    }
    template<class T, size_t N>
    std::array<T, N> copy_even_if_rvalue(T(&arr)[N]) {
      return details::copy_even_if_rvalue(arr, std::make_index_sequence<N>{} );
    }
    template<class T, size_t N>
    std::array<T, N> copy_even_if_rvalue(T(&&arr)[N]) {
      return copy_even_if_rvalue(arr); // forward to lvalue version
    }
    

    will copy both rvalues and lvalues. Usually copy is a smarter operation than copy_even_if_rvalue in my opinion.

    copy_even_if_rvalue will convert raw C arrays into std::arrays, because that is about the only sensible way to copy them. An =delete overload would be the other reasonable option.