Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template deduction: const reference and const pointer

template <typename T>
void f(T t)
{}

int x = 1;
const int & rx = x;
const int * px = &x;
f(rx); // t is int
f(px); // t is const int *, instead of int *, WHY???

I'm confused now. According to Effective Modern c++,

It’s important to recognize that const is ignored only for by-value parameters. As we’ve seen, for parameters that are references-to- or pointers-to-const, the constness of expr is preserved during type deduction.

I think it means

template <typename T>
void f(T * t)
{}
f(px); // t is const int *

template <typename T>
void f(T & t)
{}
f(cx); // t is const int &

template <typename T>
void f(T t)
{}
f(value); // const or volatile of value will be ignored when the type of the parameter t is deduced

So I think when f(px) above, t should be int *, but in fact it is const int *.

Why the const of reference is ignored but the const of pointer isn't? Or, why isn't rx const int &?

like image 356
Yves Avatar asked Oct 21 '16 02:10

Yves


People also ask

Is reference same as const pointer?

A reference is an alias for an already existing variable. Once a reference is initialized to a variable, it cannot be changed to refer to another variable. Hence, a reference is similar to a const pointer.

What is the use of const reference in C++?

For instance, const references allow you to specify that the data referred to won't be changed; this means that you can use const references as a simple and immediate way of improving performance for any function that currently takes objects by value without having to worry that your function might modify the data.

What is the use of const pointer?

We can create a pointer to a constant in C, which means that the pointer would point to a constant variable (created using const). We can also create a constant pointer to a constant in C, which means that neither the value of the pointer nor the value of the variable pointed to by the pointer would change.

Should I always use const reference?

Yes, you should use const whenever possible. It makes a contract that your code will not change something. Remember, a non-const variable can be passed in to a function that accepts a const parameter.


2 Answers

So I think when f(px) above, px should be int *, but in fact it is const int *.

The point is the type of parameter, behaviors change for passed-by-value and passed-by-reference/pointer.

When passed-by-value, the constness of the argument itself is ignored. For a pointer parameter, the constness of pointer is ignored (const pointer -> pointer), but the constness of pointee is still preserved (pointer to const -> pointer to const).

It does make sense because when pass a pointer, the pointer itself is copied, but the pointee is the same, they're both pointing to the same thing, so constness of pointee is preserved; from the point of callers, they won't want the object to be modified, they might use it later. While pass a reference (reference doesn't matter in fact here), you'll get a brand new value copied, which has nothing to do with the original one, then constness is ignored.

As the following explanations in the book, when const pointer to const (a const char* const) passed,

template<typename T>
void f(T param); // param is still passed by value

const char* const ptr = // ptr is const pointer to const object
  "Fun with pointers";

f(ptr); // pass arg of type const char * const

The type deduced for param will be const char*.

like image 171
songyuanyao Avatar answered Sep 19 '22 23:09

songyuanyao


Only top-level const/volatile qualifiers are ignored. All others are inherent qualities of your type. In other words, you're copying a pointer - it means the function operates on a copy and any modifications to it (like assigning another variable's address) do not modify the original pointer. But if you pass a pointer to const int, having the function modify the integer is very much counter-intuitive.

template <typename T>
void f(T t)
{
    t = &another_variable; // ok
}

f(px);

and

void f(T t)
{
    *t = 42; // not ok!
}

f(px); // secretly modifying `x` through a pointer to const...

Reference: this answer for pointer to const vs. const pointer differences

like image 26
krzaq Avatar answered Sep 23 '22 23:09

krzaq