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.
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.
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.
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.
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.
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.
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With