Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a const reference to a reference lose its constness?

Given this code:

#include <iostream>  template<typename T> void modify(const T &j){ j = 42; } // j has type int&  int main() {     int i = 10;     modify<int&>(i); // T=int&     std::cout << i;  // 42 is printed } 

Why does const T &j become int &j if T=int&? What happens to const?

like image 917
Kane Avatar asked May 15 '20 15:05

Kane


People also ask

Does const reference copy?

Not just a copy; it is also a const copy. So you cannot modify it, invoke any non-const members from it, or pass it as a non-const parameter to any function. If you want a modifiable copy, lose the const decl on protos .

Can you change the value of const reference?

Because the reference is a const reference the function body cannot directly change the value of that object.

Can a const reference be bound to a non const object?

No. A reference is simply an alias for an existing object. const is enforced by the compiler; it simply checks that you don't attempt to modify the object through the reference r .

Is const reference an lvalue?

Such a reference is called an lvalue reference to a const value (sometimes called a reference to const or a const reference). In the above program, we bind const reference ref to modifiable lvalue x . We can then use ref to access x , but because ref is const, we can not modify the value of x through ref .


1 Answers

There is no such thing as reference to a reference i.e. there is no T & &.

Given a const T& where T is int&, the type collapses into int&.

What happens to const?

There is no such thing as a const reference either i.e. there is no T & const (not to be confused with reference to const, which does exist and which is quite often colloquially called const reference). No reference can be modified (which would be different from modifying the referred object), so constness is not meaningful. The const is simply ignored here.

Standard rule (from latest draft):

[dcl.ref] If a typedef-name ([dcl.typedef], [temp.param]) or a decltype-specifier ([dcl.type.simple]) denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR. [ Note: This rule is known as reference collapsing. — end note ]

Here cv refers to cv-qualifiers i.e. const and volatile.

To clarify why this applies to template arguments:

[temp.param] A type-parameter whose identifier does not follow an ellipsis defines its identifier to be a typedef-name ...


P.S. The way reference collapsing is specified is part of the reason why perfect forwarding works.

like image 107
eerorika Avatar answered Oct 07 '22 21:10

eerorika