views:

134

answers:

6

The following example is working when I manualy replace T wirh char *, but why is not working as it is:

template <typename T>
class A{
  public:
    A(const T _t) { }
};

int main(){
  const char * c = "asdf";
  A<char *> a(c);
}

When compiling with gcc, I get this error:

test.cpp: In function 'int main()':
test.cpp:10: error: invalid conversion from 'const char*' to 'char*'
test.cpp:10: error:   initializing argument 1 of 'A<T>::A(T) [with T = char*]'
A: 

Try converting to const T&. Also, in these cases, you should let the compiler automatically deduce the template argument, and not specify it.

DeadMG
+1  A: 

If you eliminate the const before c's assigning, the program will compile.

What's happening is that the constructor is not necessarily taking a const version of an instance. const is telling the constructor that you cannot change the data in T _t, which is not actually a const object within the scope of the constructor... it's a very subtle but important distinction to make.

Legatou
+8  A: 

Substituting T with char* gives a const pointer to char, while c is declared as a pointer to const char.

A solution would be to take pointers and integral types by value and class types by const reference. If you can, use Boost Call Traits which solves these kinds of problems for you.

Georg Fritzsche
+1  A: 

I guess it's because your function expects const (char *) (since T is char *), i.e. you can't change the address it points to, while const char * stands for (const char) *, i.e. you can't change the value on the place the pointer points to.

petersohn
+1  A: 

What's happening here is that the compiler knows that your template is instantiated with T = char* and first of all tries to see if the value you provide (c) is a char* (it is not; it's a const char*) before checking its const-ness.

Therefore you need to either:

  1. const_cast the value c
  2. Specify A<const char *> a(c);
  3. Remove the const specifier from the declaration of A's constructor

The best of these to do is #3. This will lose you what I assume is a "guarantee" you need: that the value used to initialize objects of class A is constant. To achieve this again, you will have to use some implementation of type traits and template constraints to ensure that the template cannot be instantiated when T is not a const type.

Jon
Don't `const_cast` pointers to `const` data unless your requirements include undefined behaviour.
Georg Fritzsche
A: 

If you make your constructor A(const char* _t), you're getting effectively A( (const char) *t). That is, a pointer to const char. But when you specify char* as the template parameter, you're getting effectively A( const (char *t)), or a const pointer to char.

In other words, I think you have the same problem discussed in the article A Midsummer Night's Madness, except with template parameters instead of typedefs.

Fred Larson