"Transparent" function: perfectly forwarding an argument to the return value

4 days ago 8
ARTICLE AD BOX

I'm trying to figure out how the signature of a completely transparent function might look. That is, a function that takes an argument T and that itself (i.e. from its return value) then looks exactly like a T. That is, a function that forwards its argument to its return value.

Consider this example:

#include <utility> template<typename T> T&& manipulate(T&& t) { /* manipulate t (but do not move from t - t stays valid) */ return std::forward<T>(t); } class C { }; void fun1(C &&) { } void fun2(C &) { } int main() { C x; // Examples: C a = manipulate(C()); // 1: ok C b = manipulate(x); // 2: ok C& c = manipulate(x); // 3: ok // C& d = manipulate(C()); // 4: not ok fun1( manipulate(C()) ); // 5a: ok? // fun2( manipulate(C()) ); // 5b: not ok? // fun2( manipulate(C()) ) // 6a: not ok? fun2( manipulate(x) ); // 6b: ok? }

So this obviously revolves around the universal reference T&&.

I think I can figure out the first four examples by means of reference-collapsing:

give Rvalue -> T is C, t is Rvalue-ref inside, return type is Rvalue-ref, that is moved-into a on return

give Lvalue -> T is C&, t is Lvalue-ref inside, return type is Lvalue-ref, that is copied-into b (b=... is an initialization, uses copy-ctor)

give Lvalue -> T is C&, t is Lvalue-ref inside, return type is Lvalue-ref -> c is bound to x

give Rvalue -> T is C, t is Rvalue-ref inside, return type is Rvalue-ref -> cannot bind that to a reference

The last two give me a bit of a headache. They do seem to behave as expected, but I don't feel like I can explain why. Is my approach watertight?

I found a bit of a related answer here.

Read Entire Article