samedi 3 mars 2018

Universal reference: returning T when given T&& and T& when given T&

Consider a class A, how can I write a template having the same behaviour as

A& pretty(A& x)
{
    /* make x pretty */
    return x;
}

A pretty(A&& x)
{
    /* make x pretty */
    return x;
}

Knowing that I want to:

  1. modify the argument (x) in the exact same way, independently of whether the parameter is an rvalue reference or an lvalue reference (in fact, the two sections /* make x pretty */ are identical), hence having a single function;

  2. avoid unnecessary copying;

  3. be able to use the function to modify a variable;

  4. be able to "pipeline" the function call, no matter if the argument is an rvalue or an lvalue.

As an example for 2. and 3., consider the following use case:

void read_A(const A& x) { /* ... */ }
void take_A(A&& x)      { /* ... */ }

A x();
read_A(pretty(x));
take_A(pretty(A()));


My idea was to take advantage of universal references while limiting the allowed parameters to references to A. But what about the return type?

template<typename T>
std::enable_if_t<std::is_same<T, A>::value>
/*???*/ pretty(T&& x)
{
    /* make x pretty */
    return x; //?
}

Aucun commentaire:

Enregistrer un commentaire