C ++ passing const pointer to const reference

Hmm, weird in VC2012. I can not imagine the syntax for passing a const pointer by a const reference to a function of a template class whose template argument is not a const pointer, i.e.

template<typename T> struct Foo { void Add( const T& Bar ) { printf(Bar); } }; void main() { Foo<char*> foo; const char* name = "FooBar"; foo.Add(name); // Causes error } 

So, I have simplified my problem, but basically I want the “Add” argument to have the constant T ie const char *. I tried:

 void Add( const (const T)& Bar ); typedef const T ConstT; void Add( const (ConstT)& Bar ); void Add( const typename std::add_const<T>::type& Bar ); 

None of them work. The exact error I get is:

 error C2664: 'Foo<T>::Add' : cannot convert parameter 1 from 'const char *' to 'char *const &' with [ T=char * ] Conversion loses qualifiers 

which I see correctly, but how can I solve it without creating a "name" const, but not const.

+6
source share
5 answers

It looks like your problem is here, once you have a pointer type mapped to a template type, you can no longer add a constant to the specified type, only to the pointer itself. It looks like you are trying to do this, automatically add a constant to the parameter of your function (so if T is char* , the function should accept const char* const& , not char* const& , as you already wrote). The only way to do this is to use another template to add a constant to the pointer for pointer types, as shown below. I allowed to include the missing headers and fix the main signature:

 #include <cstdio> template<typename T> struct add_const_to_pointee { typedef T type; }; template <typename T> struct add_const_to_pointee<T*> { typedef const T* type; }; template<typename T> struct Foo { void Add( typename add_const_to_pointee<T>::type const & Bar ) { printf(Bar); } }; int main() { Foo<char*> foo; const char* name = "FooBar"; foo.Add(name); // Causes error } 

As mentioned in another friend, this problem just goes away if you use std::string instead of C-style strings

+2
source

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& ); // reference to a constant pointer to a // non-constant char 

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.

+7
source

You need to change the template argument to your Foo object to Foo<const char*> . Because if T=char* , then const T=char*const , not const char* . Trying to make it work is not a good idea and is likely to lead to undefined behavior.

+1
source

Using:

 Foo<const char*> foo; const char* name = "FooBar"; foo.Add(name); 

And write int main() instead of void main()

+1
source

If passing const char* instead of char* to Foo not an option, you can thin the correct type with std::remove_pointer . This will remove the pointer modifier and allow you to provide a more explicit type.

 #include <type_traits> template<typename T> struct Foo { void Add(typename std::remove_pointer<T>::type const*& Bar ) { printf(Bar); } }; 

To prevent the pointer value from changing, you can also declare the link as const .

 void Add(typename std::remove_pointer<T>::type const* const& Bar ) { Bar = "name"; } // <- fails 

If you need to reduce the type by pointing to a pointer, you can use std::decay along with std::remove_pointer

 void Add(typename std::remove_pointer<typename std::decay<T>::type>::type const*& Bar) { printf(Bar); } 

It really depends on your T requirements. I suggest assuming that only the base type (e.g. char ) is passed as T and builds a reference to it and pointer types.

+1
source

All Articles