Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is T const&& not a forwarding reference?

In the context of a template, the following "reference collapsing" rules are applied:

template <typename T>
void foo(T && t)
{
    //T&  &   -> T&
    //T&  &&  -> T&
    //T&& &   -> T&
    //T&& &&  -> T&&
}

Why does the language prohibit "universal references" from having const qualifiers?

template <typename T>
void foo(T const && t)

It would seem to make sense if the type had resolved to a reference (3 out of the 4 cases).

I'm sure this idea is incompatible with some other design aspect of the language, but I can't quite see the full picture.

like image 717
Trevor Hickey Avatar asked Sep 03 '16 05:09

Trevor Hickey


People also ask

What is const T?

T * const would mean you can modify the T value pointed to by foo , but you cannot modify the pointer itself; so you can't say foo++; (*foo)++ because the first statement would increment (modify) the pointer.

Why does const exist?

It is simple in concept: variables declared with 'const' added become constants and cannot be altered by the program. However it is also used to bodge in a substitute for one of the missing features of C++ and there it gets horridly complicated and sometimes frustratingly restrictive.

What does const int* mean?

int const* is pointer to constant integer This means that the variable being declared is a pointer, pointing to a constant integer. Effectively, this implies that the pointer is pointing to a value that shouldn't be changed.

What is const& in c++?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.


1 Answers

Originally the rvalue reference proposal said that the transformation happens if P is "an rvalue reference type". However, a defect report later noticed

Additionally, consider this case:

template <class T> void f(const T&&);
...
int i;
f(i);

If we deduce T as int& in this case then f(i) calls f<int&>(int&), which seems counterintuitive. We prefer that f<int>(const int&&) be called. Therefore, we would like the wording clarified that the A& deduction rule in 14.8.2.1 [temp.deduct.call] paragraph 3 applies only to the form T&& and not to cv T&& as the note currently implies.

There appears to have been a time period where const T &&, with T being U&, was transformed to const U&. That was changed to be consistent with another rule that says that const T, where T is U& would stay U& (cv-qualifiers on references are ignored). So, when you would deduce T in above example to int&, the function parameter would stay int&, not const int&.

In the defect report, the reporter states "We prefer that f<int>(const int&&) be called", however provides no reason in the defect report. I can imagine that the reason was that it seemed too intricate to fix this without introducing inconsistency with other rules, however.

We should also keep in mind that the defect report was made at a time where rvalue references could still bind to lvalues - i.e const int&& could bind to an int lvalue. This was prohibited only later on, when a paper by Dave & Doug, "A Safety Problem with RValue References", appeared. So, it seems to me that a deduction that works (at that time) was worth more than a deduction that simply was counter intuitive and dropped qualifiers.

like image 164
Johannes Schaub - litb Avatar answered Sep 19 '22 05:09

Johannes Schaub - litb