【问题标题】:What's wrong with this use of template?这种使用模板有什么问题?
【发布时间】:2016-12-06 10:38:02
【问题描述】:

这是我第一次在课堂上使用模板。这是我的尝试。

MyCairoControl.h:

#ifndef _MYCAIROCONTROL_
#define _MYCAIROCONTROL_

template<class T>
class MyCairoControl : public IControl 
{
private:
    T *pPlug;

public:
    MyCairoControl(T *plug, IRECT container);
    ~MyCairoControl();
};

#endif // !_MYCAIROCONTROL_

MyCairoControl.cpp:

#include "MyCairoControl.h"

MyCairoControl::MyCairoControl(T *plug, IRECT container) : IControl(plug, container), pPlug(plug) {
       // t->somethings();
}
MyCairoControl::~MyCairoControl() {

}

但它说“T”是未定义的,所以我不能使用那个 CTOR。在类上使用模板不是正确的方法吗?

【问题讨论】:

标签: c++ templates


【解决方案1】:

由于MyCairoControl 是一个类模板,它的方法定义也必须是模板,匹配类的模板参数:

template <class T>
MyCairoControl<T>::MyCairoControl(T *plug, IRECT container){
     /* ... */
}

template <class T>
MyCairoControl<T>::~MyCairoControl() { 
     /* ... */
}

wandbox example


这也意味着定义必须在编译期间始终可用,而不是链接 - 它们需要存在于头文件中。

This article("如何在.h文件中定义模板类并在.cpp文件中实现")对问题进行了全面的解释。

【讨论】:

  • 我认为 OP 更大的问题是将模板定义永无止境地放在单独的源文件中。
  • @paizza:是的,这很烦人......尤其是当您有多个模板参数并且方法也被模板化时!一种可能的替代方法是在类 (in-place) 中定义方法,这样可以减少一些重复,但可能会使代码更难阅读 (由于接口和实现之间缺乏分离) .
  • 如果您知道可能使用的类型,则无需将实现放在标题中。
  • @VittorioRomeo;我不明白你是什么意思。例子?
  • @paizza: here's an example 我提到的问题。这是an example of in-place definition
【解决方案2】:

需要在实现文件中重新声明T为模板类型名:

#include "MyCairoControl.h"

template<class T>
MyCairoControl<T>::MyCairoControl(T *plug, IRECT container) : IControl(plug, container), pPlug(plug) {
       // t->somethings();
}


template<class T>
MyCairoControl<T>::~MyCairoControl() {

}

原来的问题有两个。首先,T 作为符号需要被称为模板参数。添加到实现签名的template&lt;class T&gt; 行就是这样做的——它定义了T 的含义。其次,你需要意识到构造函数和析构函数——实际上,任何成员——所属的类型不再是MyCairoControl,而是MyCairoControl&lt;T&gt;。范围解析运算符的左侧现在需要是那个。

还有一个问题需要注意。就目前而言,类成员的实现与标头位于单独的文件中,这可能会出现问题。该类的使用者将包含标头而不是源文件,因此他们将无法使用模板 - 例如,如果他们尝试使用MyCairoControl&lt;Foo&gt;,他们将得到未解决的符号错误。如果您知道将用于T 的类型,则可以修复此问题。具体来说,如果您在MyCairoControl.cpp 中声明专业化如下:

template <>
class MyCairoControl<Foo>;

template <>
class MyCairoControl<Bar>;

任何人都可以使用MyCairoControl&lt;Foo&gt;MyCairoControl&lt;Bar&gt;,但尝试使用MyCairoControl&lt;OtherType&gt; 仍然会出现未解决的外部符号错误,除非您也为其添加前向声明。

【讨论】:

  • 当然我试过了,但是它在析构函数周围写着argument list for class template "MyCairoControl" is missing...
  • 抱歉 - 我遗漏了一些内容 - 已修复。 (具体来说: 参数是针对类的,必须在类名上,而不仅仅是针对函数。我看错了问题。)
猜你喜欢
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多