模板方法专门化链接错误

Sam*_*rsa 9 c++ templates c++03

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

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

int main()
{
  MyClass m;
  m.foo<double>();
  m.foo<float>();
}
Run Code Online (Sandbox Code Playgroud)
// 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>();

};
Run Code Online (Sandbox Code Playgroud)
// myClass.cpp
#include "myClass.h"

template <>
void MyClass::foo<float>()
{
  cout << "Template function<float> called" << endl;
}
Run Code Online (Sandbox Code Playgroud)

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

我认为原因可能是该方法未被显式实例化(尽管完全特template class化不需要显式实例化以进行正确的链接).如果我尝试显式实例化该方法,我会收到此错误:

错误C3416:'MyClass :: foo':可能无法显式实例化显式特化

所以问题是:

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

jog*_*pan 15

虽然WhozCraig的答案(现已删除)提供了正确的代码来解决您的问题,但以下是您的问题的一些直接答案,包括对您的代码的评论:

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

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

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

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

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

      template <>
      void MyClass::foo<float>();
    
    Run Code Online (Sandbox Code Playgroud)

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

    (§14.7.3/ 6)如果一个模板,一个成员模板或一个类模板的成员被明确地专门化,那么该特化应该在该特化的第一次使用之前被声明,这将导致一个隐式的实例化,发生这种用途的翻译单位; 无需诊断.[...]

  4. 由于所有特化都是显式的(即完全特化,使用你的单词),因此不需要显式实例化,但它们是可能的(§14.7.2).您可以将它们放在.cpp文件的末尾,语法如下:

    template void MyClass::foo<float>();
    template void MyClass::foo<int>();
    
    Run Code Online (Sandbox Code Playgroud)

    同样,这仅对没有自己的显式特化的类型非常有用.

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

.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>();
Run Code Online (Sandbox Code Playgroud)

的.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>();
Run Code Online (Sandbox Code Playgroud)

  • +1.*谢谢*.#4是我完全放大脑的部分.我不明白需要处理给定的先决条件.我很确定其余的都没问题.这是一个可靠的答案,标准的引用使它更适合这个问题,所以我将完全放弃我的答案并赞成这一点.在你闲暇时从身体上移除我的参考.我很高兴我没有想到深陷. (2认同)