Search code examples
c++templatespointersreferencetemplate-argument-deduction

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 &?


Solution

  • 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*.