3

Я новичок в шаблонах на C++. Может кто-нибудь объяснить, почему мой специализированный конструктор никогда не будет выполнен. Он работает, когда я удаляю оператор const и reference.Специализация для конструктора класса шаблона

#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"); 
} 

Выход

Шаблон

Шаблон

+1

'main' должен возвращать' int', а не 'void'. Кроме того, заголовок для 'strcpy' и' strlen' равен '', а не ''. – dyp

+2

Строковый литерал - это массив lvalue, который может быть преобразован в prvalue указателя.Указатель prvalue не может связываться с ссылкой на не константу lvalue, как 'const char * &'. Вот почему называется первый ctor. – dyp

+1

Кстати, это не частичная специализация. Это явная специализация одной функции-члена. – dyp

ответ

5

Поскольку вы не можете связать "Hello" - const char*&.

dyp информация добавлена ​​в комментариях довольно интересно:

Строковый литерал именующее массив, который может быть преобразован в указатель prvalue. Указатель prvalue не может связываться с неконстантной ссылкой Lvalue как сопзИте полукокс * &

Что означает, что вы можете на самом деле сделать его работу, заменив const char*& на const char* const&, или даже const char* && в C++ 11, не уверен, если это действительно разумно в вашем случае использования.

+0

* «Это означает, что вы действительно можете заставить его работать» * Или вы просто используете 'const char *' без каких-либо ссылок. Я не уверен, что OP намеревается сделать. – dyp

+0

@Drax, чтобы соответствовать объявлению шаблона, вы должны использовать 'char * const &'. –

2

UPDATE Я получил все, что неправильно, полностью переписал ответ.

Во-первых, этот конструктор

template<> 
CData<char*>::CData(const char* &Str) 

не специализация CData(const T&), потому что Str параметром здесь является неконстантная ссылка на указатель на const char. Таким образом, это определение не шаблонного конструктора CData(const char*&).

Во-вторых, "Hello" имеет тип «массив n const char» (см. What is the type of string literals in C and C++?), поэтому его нельзя преобразовать в неконстантную ссылку. Вот почему вызывается конструктор «Шаблон».

Правильная специализация

template<> 
CData<char*>::CData(char* const& Str) 

То есть, он принимает константную ссылку на char*.

И после этого вы должны удалить CData(const char*&), если вам не нужно, например, этот код для компиляции:

const char* foo = "foo"; 
CData<int> obj2(foo); 

Так вот код:

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

Правильный способ фиксации выше предупреждения является добавьте другую специализацию:

template<> 
CData<const char*>::CData(const char* const& Str) 
{ 
    ... 
} 

CData<const char*> obj2("Hello"); // calls CData(const char* const&) 
+0

@dyp спасибо, я исправил ответ. Что касается ссылки, там также рассматриваются строковые литералы C++. –

+0

Ой, ой, я только прочитал половину первого ответа и посмотрел на остальных. – dyp