Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)

like image 395
tohava Avatar asked Dec 24 '22 22:12

tohava


2 Answers

What about this?

template <typename T>
T copy(T t) {return t;}

The copy is done when you pass t by value and a following move take place.

http://coliru.stacked-crooked.com/a/cbc1a161f65a022b


If you can modify your function to:

void func(A) {}

then you can do

int main() {
   A a;
   func(a);            //copies
   func(std::move(a)); //moves
   return 0;
}

Without any extra constructor call.

http://coliru.stacked-crooked.com/a/1bc80bcce64f242f

like image 92
DarioP Avatar answered Apr 26 '23 16:04

DarioP


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.

like image 27
Yakk - Adam Nevraumont Avatar answered Apr 26 '23 17:04

Yakk - Adam Nevraumont