Template argument deduction and const qualification
c++, templates
Solution
There is no template deduction in your example. `Derived<int*> d(p);` specifically sets the template parameter to `T` to `int*` (pointer to int). Your derived constructor takes a `const T` parameter which is a const pointer to int in this case. I think your confusion is because `const int* p;` does not declare a const pointer to int, but instead declares a pointer to const int which is not, and cannot be converted to, a const pointer to int (the former lets you modify the pointed to value while the latter does not).
Remember that C and C++ declarations are generally read from the variable name outwards, so for `const int* p` you start at `p`, go left and see `*` and then go farther left and see `const int`, so `p` is a pointer to a const int. Here is a good guide on deciphering C declarations and cdecl is also a very useful tool.
The problem with your example is `p` is a pointer to const int, but the constructor of `Derived<int*>` takes a const pointer to int since `T` is `int*`. This may seem confusing, but you can think of `const` as having a higher precedence than `*` in type declarations. So in `const int *` the `const` applies to `int` and then `*` applies to the whole thing making `p` a pointer to const int whereas for `const T`, the const applies to `T`, which is actually `int*` so `const T argD` makes `argD` a const pointer to int.
Using this same idea all your `Foo` examples can be easily deciphered.
Foo(T& a) // a is a reference to a value of type T
Foo(T a) // a is a value of type T
Foo(T* a) // a is a pointer to a value of type T
Foo(const T a) // a is a constant value of type T
Foo(const T* a) // a is a pointer to a constant value of type T
Foo(const T& a) // a is a reference to a constant value of type T
In general only `Foo(T a)` and `Foo(const T a)` cannot be overloaded because it doesn't matter to the caller whether the argument is copied into a constant variable or not.
More specifically, if `T` is `char *` (pointer to char)
Foo(char *&a) // a is a reference to a pointer to a char
Foo(char *a) // a is a pointer to a char (*)
Foo(char **a) // a is a pointer to a pointer to a char
Foo(char *const a) // a is a constant pointer to a char (cannot overload with (*))
Foo(char *const *a) // a is a pointer to a constant pointer to a char
Foo(char *const &a) // a is a reference to a constant pointer to a char
If `T` is `const char*` (pointer to a const char) things are much the same
Foo(const char *&a) // a is a reference to a pointer to a const char
Foo(const char *a) // a is a pointer to a const char (*)
Foo(const char **a) // a is a pointer to a pointer to a const char
Foo(const char *const a) // a is a constant pointer to a const char (cannot overload with (*))
Foo(const char *const *a) // a is a pointer to a constant pointer to a const char
Foo(char *const &a) // a is a reference to a constant pointer to a const char
If `T` is `char* const` (const pointer to a char) then all the `const T` overloads are redundant because `const T` is equivalent to `T` when `T` is already const.
Foo(char *const &a) // a is a reference to a const pointer to a char (+)
Foo(char *const a) // a is a const pointer to a char (*)
Foo(char *const *a) // a is a pointer to a const pointer to a char (^)
Foo(char *const a) // a is a const pointer to a char (same as (*))
Foo(char *const *a) // a is a pointer to a const pointer to a char (same as (^))
Foo(char *const &a) // a is a reference to a const pointer to a char (same as (+))
Problem
Could anyone explain why the code does not compile. ``` template<class T, class DER> struct Base { T a; Base(const T argB) : a(argB){} }; template<class T> struct Derived : Base<T, Derived<T> > { Derived(const T argD) : Base<T, Derived<T> >(argD){} }; int main() { int val = 10; const int *p = &val; /* this was in the original question Derived<int*> d(p); // breaks, but compiles with Derived<const int*> d(p); */ Derived d(p); // fails, but Derived<const int*> d(p); compiles } ``` The error message is that about no conversion from `int*` to `const int*`. As I see it `T` can be substitues by `int*` and in that case the constructor to `Derived` receives its argument as a `const int*` and invokes the base with `const int*`. Why then is the constant qulaification getting lost. I clearly do not understand how template argument deduction works. I have not been able to find any lucid but rigorous and exhaustive description of how it works when `const`, `*` and `&` are in play. That is, what will `a` get type deduced to in these various cases. ``` Foo(T& a) Foo(T a) Foo(T* a) Foo(const T a) Foo(const T*a) Foo(const t&a) ``` when `a` is - an object, - a pointer and - an array.