【问题标题】:Specialisation for template class constructor模板类构造函数的特化
【发布时间】:2014-08-27 13:13:23
【问题描述】:

我是 C++ 模板的新手。 谁能解释为什么我的专用构造函数永远不会被执行。 当我删除 const 和引用运算符时它可以工作。

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

输出是

模板

模板

【问题讨论】:

  • main 必须返回 int,而不是 void。此外,strcpystrlen 的标头是 &lt;cstring&gt;,而不是 &lt;string&gt;
  • 字符串文字是一个数组左值,可以转换为指针纯右值。指针纯右值不能绑定到像const char* &amp; 这样的非常量左值引用。这就是调用第一个 ctor 的原因。
  • 顺便说一下,这不是部分专业化。它是单个成员函数的显式特化。
  • 请注意,在第二次调用中选择第一个 ctor 使用了一个不推荐使用的转换:const T&amp; for T == char* 产生一个char* const&amp;,这需要转换 6 数组 @987654333将字符串文字的@ 转换为char*(非常量)。

标签: c++ templates template-specialization partial-specialization


【解决方案1】:

因为您无法将"Hello" 绑定到const char*&amp;

cmets中添加的dyp的信息很有意思:

字符串字面量是一个数组左值,可以转换为指针纯右值。指针纯右值不能绑定到非 const 左值引用,如 const char* &

这意味着您实际上可以通过将const char*&amp; 替换为const char* const&amp; 甚至在c++11 中的const char* &amp;&amp; 来使其工作,但不确定这在您的用例中是否真的很聪明。

【讨论】:

  • “这意味着您实际上可以让它工作” 或者您只需使用 const char* 而无需任何参考。不过,我不确定 OP 打算做什么。
  • @Drax 匹配模板声明你应该使用char* const&amp;
【解决方案2】:

更新我弄错了,完全重写了答案。

首先,这个构造函数

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

不是CData(const T&amp;) 的特化,因为这里的Str 参数是一个非常量引用,指向const char 的指针。所以是非模板化构造函数CData(const char*&amp;)的定义。

其次,"Hello" 的类型为“array of 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*&amp;),除非你需要例如这个代码来编译:

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

【讨论】:

  • @dyp 谢谢,我更正了答案。关于链接,那里还介绍了 C++ 字符串文字。
  • 哦,哎呀,我只看了第一个答案的一半,看了一眼其他答案。
猜你喜欢
  • 1970-01-01
  • 2011-05-08
  • 2011-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-04
  • 1970-01-01
相关资源
最近更新 更多