Specialization for the constructor of template classes
I am new to C ++ templates. Can someone please explain why my custom constructor will never get executed. It works when I remove the const and reference operator.
#include<iostream>
#include<string>
using namespace std;
template<typename T>
class CData
{
public:
CData(const T&);
CData(const char*&);
private:
T m_Data;
};
template<typename T>
CData<T>::CData(const T& Val)
{
cout << "Template" << endl;
m_Data = Val;
}
template<>
CData<char*>::CData(const char* &Str)
{
cout << "Char*" << endl;
m_Data = new char[strlen(Str) + 1];
strcpy(m_Data, Str);
}
void main()
{
CData<int> obj1(10);
CData<char*> obj2("Hello");
}
Output signal
Template
Template
source to share
Since you cannot bind "Hello"
to const char*&
.
The dyp info added in the comments is pretty interesting:
A string literal is an lvalue array that can be converted to a pointer prvalue. A prvalue pointer cannot bind to a constant reference l const like const char * &
This means that you can make it work by replacing it const char*&
with const char* const&
or even const char* &&
C ++ 11, but not sure if this is really reasonable in your use case.
source to share
UPDATE I got it wrong, completely rewrote the answer.
First this constructor
template<>
CData<char*>::CData(const char* &Str)
is not a specialization CData(const T&)
, since here the parameter Str
is a non-const reference to a pointer to const char
. Therefore, this definition is not a templated constructor CData(const char*&)
.
Second, it "Hello"
is of type "array n const char
" (see What is the type of string literals in C and C ++? ) So that it can't be converted to a non-const reference. This is why the Template constructor is called.
Correct specialization
template<>
CData<char*>::CData(char* const& Str)
That is, it accepts a const reference to char*
.
And after that you have to remove CData(const char*&)
, if you don't need, for example, this code to compile:
const char* foo = "foo";
CData<int> obj2(foo);
So here's the code:
template<typename T>
class CData
{
public:
CData(const T&);
private:
T m_Data;
};
template<typename T>
CData<T>::CData(const T& Val)
{
....
}
template<>
CData<char*>::CData(char* const& Str)
{
....
}
// warning: deprecated conversion from string constant to 'char*'
CData<char*> obj2("Hello"); // calls CData(char* const&)
The correct way to address the above warning is to add another specialization:
template<>
CData<const char*>::CData(const char* const& Str)
{
...
}
CData<const char*> obj2("Hello"); // calls CData(const char* const&)
source to share