There is a big difference between a pointer to a constant object ( T const* or const T* ) and a constant pointer to a non-constant object ( T * const ). In your case, the signature of the Add member:
void Foo<char *>::Add(char * const& );
I usually recommend that people abandon the use of const on the left for precisely this reason, as newbies usually confuse typedef (or inferred types) with type substitutions and when they read:
const T& [T == char*]
They misinterpret
const char*&
If const is in the right place:
T const &
It’s easier for beginners, since a simple mental replacement works:
char * const &
Another problem you ask, but perhaps what you think is necessary is:
Given the type of T , it has a function that takes U , which is const T if T not a pointer type, or X const * if T is a pointer to X
template <typename T> struct add_const_here_or_there { typedef T const type; }; template <typename T> struct add_const_here_or_there<T*> { typedef T const * type; };
Then you can use this in your signature:
template <typename T> void Foo<T>::Add( const typename add_const_here_or_there<T>::type & arg ) { ...
Please note that I add two const characters to the signature, so in your case char* will be displayed on char const * const & , since it seems like you want to pass const& to something, and you also want the type const .
You might have wondered about the name of the metafile: * add_const_here_or_there *, this is similar to why: there is no easy way to describe what you are trying to do, which is usually a code smell. But here you have your decision.