11

考虑以下头文件和源文件:

// main.cpp
#include "myClass.h"

int main()
{
  MyClass m;
  m.foo<double>();
  m.foo<float>();
}

// myClass.h
#pragma once

#include <iostream>

using namespace std;

class MyClass
{
public:

  template <typename T>
  void foo()
  {
    cout << "Template function<T> called" << endl;
  }

  template <>
  void foo<int>()
  {
    cout << "Template function<int> called" << endl;
  }

  template <>
  void foo<float>();

};

// myClass.cpp
#include "myClass.h"

template <>
void MyClass::foo<float>()
{
  cout << "Template function<float> called" << endl;
}

foo<float>我得到一个关于专业化的链接错误。如果我将专业化的定义放在头文件中,那么一切都会按预期工作。

我认为原因可能是该方法没有显式实例化(尽管完全专业化template class不需要显式实例化来正确链接)。如果我尝试显式实例化该方法,则会收到此错误:

错误 C3416:“MyClass::foo”:可能未显式实例化显式特化

所以问题是:

  • 有没有办法在cpp文件中定义专业化并正确链接?
  • 如果不是,为什么不呢?我可以显式地实例化非专门化的模板方法。为什么完全专业化不一样?
4

1 回答 1

17

尽管 WhozCraig 的答案(现已删除)提供了解决您问题的正确代码,但这里有一些直接回答您的问题,包括对您的代码的评论:

  1. foo<int>()并且foo<float>()是成员模板的显式特化。那些不能出现在它们所属的类的定义中。该标准说:

    (§14.7.3/3) [...] 类或类模板的定义应在类或类模板的成员模板的显式特化声明之前。[...]

    所以你必须把它们放在类定义之后。

  2. 在头文件中完全定义的情况下foo<int>,这意味着您必须将单词放在inline定义之前;否则,如果头文件包含在多个翻译单元中,链接器就会遇到麻烦。

  3. 的特化foo<float>()定义在一个单独的文件中,该文件稍后链接到main.cpp. 这是可能的,但它要求在头文件中给出它的声明(你已经这样做了,但你必须在类定义之外这样做):

      template <>
      void MyClass::foo<float>();
    

    这是必需的,因为标准中的另一个声明:

    (§14.7.3/6) 如果模板、成员模板或类模板的成员是显式特化的,则应在第一次使用该特化之前声明该特化,这将导致发生隐式实例化,在每个发生此类使用的翻译单元;不需要诊断。[...]

  4. 由于所有特化都是显式的(即完全特化,用你的话来说),不需要显式实例化,但它们是可能的(第 14.7.2 节)。您可以将它们放在 .cpp 文件的末尾,语法为:

    template void MyClass::foo<float>();
    template void MyClass::foo<int>();
    

    同样,这仅对没有自己显式特化的类型真正有用。

因此,头文件和实现文件的正确代码如下所示:

.h 文件:

class MyClass
{
public:
  template <typename T> void foo()
  { cout << "Template function<T> called" << endl; }
};

template <> inline void MyClass::foo<int>()
{ cout << "Template function<int> called" << endl; }

template <> void MyClass::foo<float>();

.cpp:

#include "myClass.h"

template <> void MyClass::foo<float>()
{ cout << "Template function<float> called" << endl; }

/* This is unnecessary for float, but may be useful for
   types that do not have their own explicit specializations: */
template void MyClass::foo<float>();
于 2012-12-29T07:02:17.937 回答