Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rvalue reference or forwarding reference?

Tags:

c++

I know that for the following function

template <typename T>
void do_something(T&& arg);

the function parameter is a forwarding reference. But in the following case is it still a forwarding reference or an rvalue reference?

template <typename T>
class MyClass
{
    void do_something(T&& arg);
};

I think it is still a forwarding reference, but I'm not sure. Furthermore, I'd like to know what can be done to enforce an rvalue reference or a forwarding reference, if the result is not what I intended.

like image 544
Martin Fehrs Avatar asked Sep 14 '17 08:09

Martin Fehrs


People also ask

What is a forwarding reference?

I understand that a forwarding reference is "an rvalue reference to a cv-unqualified template parameter", such as in. template <class T> void foo(T&& ); which means the above function can take both l-value and r-value reference.

What are rvalue references good for?

Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

What is a forwarding universal reference?

A forwarding reference is an rvalue reference to a cv-unqualified template parameter. If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction. Hence, the two mean the same thing, and the current C++ standard term is forwarding reference.

What is the difference between L value and R value references?

An lvalue refers to an object that persists beyond a single expression. An rvalue is a temporary value that does not persist beyond the expression that uses it.


2 Answers

It's an rvalue reference. Forwarding references can only appear in a deduced context. This is just a member function that accepts an rvalue reference to the class template parameter.

You can't force a forwarding reference to be an rvalue reference if you want to maintain template argument deduction for functions. If you don't mind specifying the template argument all over the place, then this will always and only ever give an rvalue reference:

template<typename T> struct identity { using type = T; };

template<typename T> void func(typename identity<T>::type&&);

In retrospect, there actually is a way to maintain deduction but force only rvalue refs to be accepted (besides the self documenting one in Simple's answer). You can provide a deleted lvalue overload:

template<typename T>
void func(T&) = delete;

template<typename T>
void func(T&& s)
{
    // ...
}

The lvalue overload is more specialized when passed an lvalue. And on account of being deleted, will give a somewhat clear error message.

like image 103
StoryTeller - Unslander Monica Avatar answered Sep 23 '22 19:09

StoryTeller - Unslander Monica


Furthermore I like to know, what can be done to enforce an rvalue reference

If you always want an rvalue reference in a deduced context (and not a forwarding reference), then you can use this:

template<
    typename T,
    typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>
>
using rval_ref = T&&;

template<typename T>
void foo(rval_ref<T> s)
{
    // ...
}

foo can only be called with an rvalue, and T will not be a reference (i.e. if you call foo with std::string&&, then T will be std::string).

like image 25
Simple Avatar answered Sep 22 '22 19:09

Simple