Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ rvalue reference and const qualifier

Tags:

c++

c++11

Among the many benefits of const qualification is to make an API more understandable, example:

template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1

With the introduction of rvalue references, one can benefit from perfect forwarding but often const qualifiers are removed, example:

template<typename T> int function2(T&& in);
// can explicitly forward the input if it's an rvalue

Apart from documentation, is there a good way to describe that function2 won’t change its input?

like image 439
a.lasram Avatar asked Jun 09 '13 00:06

a.lasram


People also ask

Can R values be const qualified?

They are allowed and even functions ranked based on const , but since you can't move from const object referred by const Foo&& , they aren't useful.

What is const type qualifier?

The const qualifier explicitly declares a data object as something that cannot be changed. Its value is set at initialization. You cannot use const data objects in expressions requiring a modifiable lvalue. For example, a const data object cannot appear on the lefthand side of an assignment statement.

Can lvalue bind to rvalue reference?

An lvalue reference can bind to an lvalue, but not to an rvalue.

What is the difference between lvalue and rvalue references?

Now an lvalue reference is a reference that binds to an lvalue. lvalue references are marked with one ampersand (&). And an rvalue reference is a reference that binds to an rvalue. rvalue references are marked with two ampersands (&&).


2 Answers

template<typename T> int function2(T&& in);
// can explicitly forward the input if it's an rvalue

Apart from documentation, is there a good way to describe that function2 won’t change its input?

Yes. Stick with the C++03 solution:

template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1

The benefits of perfect forwarding are that you don't want to assume if something is const or non-const, lvalue or rvalue. If you want to enforce that something is not modified (i.e. that it is const), then explicitly say so by adding const.

You could do this:

template<typename T> int function1(T const&& in);
// clearly, the input won’t change through function1

However everyone who read your code would wonder why you've used rvalue references. And function1 would cease to accept lvalues. Just use const & instead and everyone will understand. It is a simple and well understood idiom.

You don't want to perfectly forward. You want to enforce immutability.

like image 137
Howard Hinnant Avatar answered Oct 13 '22 09:10

Howard Hinnant


You could say this:

template <typename T>
typename std::enable_if<immutable<T>::value, int>::type
function(T && in)
{
   // ...
}

where you have something like:

template <typename T> struct immutable
: std::integral_constant<bool, !std::is_reference<T>::value> {};

template <typename U> struct immutable<U const &>
: std::true_type {};

This way, the template will only be usable if the universal reference is either a const-reference (so T = U const &) or an rvalue-reference (so T is not a reference).


That said, if the argument is not going to be changed, you could just use T const & and be done with it, since there's nothing to be gained from binding mutably to temporary values.

like image 23
Kerrek SB Avatar answered Oct 13 '22 08:10

Kerrek SB