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

+3


source to share


2 answers


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.

+5


source


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&)

      

+2


source







All Articles