C++ 模板化类中单个方法的模板专门化

C++ 模板化类中单个方法的模板专门化,c++,visual-studio-2008,templates,specialization,C++,Visual Studio 2008,Templates,Specialization,始终考虑到包含我的模板类的以下标头包含在至少两个.CPP文件中,此代码编译正确: template <class T> class TClass { public: void doSomething(std::vector<T> * v); }; template <class T> void TClass<T>::doSomething(std::vector<T> * v) { // Do something with

始终考虑到包含我的模板类的以下标头包含在至少两个
.CPP
文件中,此代码编译正确:

template <class T>
class TClass 
{
public:
  void doSomething(std::vector<T> * v);
};

template <class T>
void TClass<T>::doSomething(std::vector<T> * v) {
  // Do something with a vector of a generic T
}

template <>
inline void TClass<int>::doSomething(std::vector<int> * v) {
  // Do something with a vector of int's
}
模板
类TClass
{
公众:
无效剂量测定法(标准::向量*v);
};
模板
void TClass::doSomething(标准::向量*v){
//用一般T的向量做点什么
}
模板
内联void TClass::doSomething(标准::向量*v){
//用int的向量做点什么
}
但是请注意专门化方法中的内联。需要避免由于多次定义该方法而导致的链接器错误(在VS2008中为LNK2005)。我理解这一点,因为完整的模板专门化与简单的方法定义是一样的

那么,如何删除
内联
?代码不应在每次使用中重复。我搜索过谷歌,在SO中阅读了一些问题,并尝试了许多建议的解决方案,但都没有成功构建(至少在VS2008中没有)


谢谢

与简单函数一样,您可以使用声明和实现。 在标题声明中输入:

template <>
void TClass<int>::doSomething(std::vector<int> * v);
模板
void TClass::doSomething(标准::向量*v);
并将实现放在您的一个cpp文件中:

template <>
void TClass<int>::doSomething(std::vector<int> * v) {
 // Do somtehing with a vector of int's
}
模板
void TClass::doSomething(标准::向量*v){
//用int的向量做something
}
别忘了删除内联(我忘了,还以为这个解决方案不起作用:))。
在VC++2005上选中

您需要将专门化定义移动到CPP文件。
即使函数未声明为模板,也允许专门化模板类的成员函数。

没有理由删除关键字inline。

无论如何,它不会改变代码的含义。

如果出于任何原因要删除内联,maxim1000的解决方案是完全有效的

不过,在您的评论中,您似乎认为inline关键字意味着包含其所有内容的函数总是内联的,但实际上这在很大程度上取决于编译器的优化

引述

有几种方法可以指定函数是内联的,其中一些 其中涉及内联关键字,其他则不涉及。不管你怎样 将函数指定为内联函数,这是编译器执行的请求 允许忽略:编译器可以内联展开部分、全部或无 调用指定为内联的函数的位置。(不要 如果这看起来非常模糊,就要气馁 以上事实上是一个巨大的优势:它可以让编译器处理大型数据 函数不同于小函数,而且它允许编译器 如果选择正确的编译器,则生成易于调试的代码 选项。)


因此,除非您知道该函数实际上会使可执行文件膨胀,或者出于其他原因希望将其从模板定义头中删除,否则您实际上可以将其保留在原处,而不会造成任何伤害

这有点麻烦,但我想我还是将其保留在这里,以防对其他人有所帮助。我在谷歌上搜索模板专门化,这让我来到了这里,虽然@maxim1000的答案是正确的,最终帮助我解决了问题,但我认为这并不十分清楚

我的情况与OP的情况稍有不同(但我认为相似到可以留下这个答案)。基本上,我使用的是一个第三方库,其中包含定义“状态类型”的所有不同类型的类。这些类型的核心只是
enum
s,但是这些类都继承自一个公共(抽象)父类,并提供不同的实用函数,例如操作符重载和
静态toString(enum类型)
函数。每个状态
enum
彼此不同且不相关。例如,一个
enum
具有字段
正常、降级、不可操作
,另一个具有
可用、挂起、缺失
,等等。我的软件负责管理不同组件的不同类型的状态。后来我想为这些
enum
类使用
toString
函数,但由于它们是抽象的,所以我无法直接实例化它们。我本来可以扩展我想使用的每个类,但最终我决定创建一个
模板
类,其中
类型名
将是我关心的任何具体状态
枚举
。关于这个决定可能会有一些争论,但我觉得这比用我自己的自定义类扩展每个抽象
enum
类并实现抽象函数要少得多。当然,在我的代码中,我只想能够调用
.toString(枚举类型)
,并让它打印该
枚举的字符串表示形式。由于所有的
enum
s都是完全不相关的,因此它们都有自己的
toString
函数,这些函数(在我学习了一些研究之后)必须使用模板专门化来调用。这让我来到这里。下面是一个MCVE的什么我必须做,以使这项工作正确。实际上,我的解决方案与@maxim1000的有点不同

这是
enum
s的头文件(大大简化)。实际上,每个
enum
类都是在自己的文件中定义的。此文件表示作为我正在使用的库的一部分提供给我的头文件:

// file enums.h
#include <string>

class Enum1
{
public:
  enum EnumerationItem
  {
    BEARS1,
    BEARS2,
    BEARS3
  };

  static std::string toString(EnumerationItem e)
  {
    // code for converting e to its string representation,
    // omitted for brevity
  }
};

class Enum2
{
public:
  enum EnumerationItem
  {
    TIGERS1,
    TIGERS2,
    TIGERS3
  };

  static std::string toString(EnumerationItem e)
  {
    // code for converting e to its string representation,
    // omitted for brevity
  }
};

不知道这是否是解决我问题的理想方案,但它对我有效。现在,不管我最终使用了多少枚举类型,我所要做的就是在.cpp文件中为
toString
方法添加几行,我可以使用已经定义的
toString
方法库,而无需自己实现它,也无需扩展我想要使用的每个
enum
类。

我想补充的是,仍然有一个很好的理由将
inline
关键字保留在那里
// file TemplateExample.h
#include <string>

template <typename T>
class TemplateExample
{
public:
  TemplateExample(T t);
  virtual ~TemplateExample();

  // this is the function I was most concerned about. Unlike @maxim1000's
  // answer where (s)he declared it outside the class with full template
  // parameters, I was able to keep mine declared in the class just like
  // this
  std::string toString();

private:
  T type_;
};

template <typename T>
TemplateExample<T>::TemplateExample(T t)
  : type_(t)
{

}

template <typename T>
TemplateExample<T>::~TemplateExample()
{

}
// file TemplateExample.cpp
#include <string>

#include "enums.h"
#include "TemplateExample.h"

// for each enum type, I specify a different toString method, and the
// correct one gets called when I call it on that type.
template <>
std::string TemplateExample<Enum1::EnumerationItem>::toString()
{
  return Enum1::toString(type_);
}

template <>
std::string TemplateExample<Enum2::EnumerationItem>::toString()
{
  return Enum2::toString(type_);
}
// and finally, main.cpp
#include <iostream>
#include "TemplateExample.h"
#include "enums.h"

int main()
{
  TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1);
  TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3);

  std::cout << t1.toString() << std::endl;
  std::cout << t2.toString() << std::endl;

  return 0;
}
BEARS1
TIGERS3