Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `const T&` not sure to be const?

template<typename T> void f(T a, const T& b) {     ++a; // ok     ++b; // also ok! }  template<typename T> void g(T n) {     f<T>(n, n); }  int main() {     int n{};     g<int&>(n); } 

Please note: b is of const T& and ++b is ok!

Why is const T& not sure to be const?

like image 327
xmllmx Avatar asked Feb 01 '19 13:02

xmllmx


People also ask

What is const T & in C++?

const T* would only forbid you to modify anything the pointer points to, but it allows you (within the bounds of the language) to inspect the value at *(foo+1) and *(foo-1) . Use this form when you're passing pointers to immutable arrays (such as a C string you're only supposed to read).

What is const T&?

const T is passed by value (copy is needed), which may be too much for a class while should be ok for built-in types. T& is passed by reference, which could be modified in the function while const T& can't, so it depends on what you need to do. Follow this answer to receive notifications.

Why is const used in c++?

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it. In C, constant values default to external linkage, so they can appear only in source files.

Why does const exist?

The purpose of const is to announce objects that may be placed in read-only memory, and perhaps to increase opportunities for optimization.


1 Answers

Welcome to const and reference collapsing. When you have const T&, the reference gets applied to T, and so does the const. You call g like

g<int&>(n); 

so you have specified that T is a int&. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& & becomes just int&. Then we get to the rule from [dcl.ref]/1, which states that if you apply const to a reference it is discarded, so int& const just becomes int& (note that you can't actually declare int& const, it has to come from a typedef or template). That means for

g<int&>(n); 

you are actually calling

void f(int& a, int& b) 

and you are not actually modifying a constant.


Had you called g as

g<int>(n); // or just g(n); 

then T would be int, and f would have been stamped out as

void f(int a, const int& b) 

Since T isn't a reference anymore, the const and the & get applied to it, and you would have received a compiler error for trying to modify a constant variable.

like image 169
NathanOliver Avatar answered Sep 28 '22 01:09

NathanOliver