链接模板类函数
Posted
技术标签:
【中文标题】链接模板类函数【英文标题】:Linking template class functions 【发布时间】:2012-08-31 10:58:44 【问题描述】:我对自己对模板的理解发现了一个挑战,我知道模板的源代码必须放在头文件中才能访问模板实例化的所有依赖类型。
所以,在这个例子中:
// This code cannot be placed in the cpp file
template <typename T> T foo(T v)
return -v;
T foo(T v)
的主体必须放在头文件中,然后,当 foo
函数在某处被实例化时,会创建“真实”主体函数,将 T
符号替换为真实类型。使用此代码:
int bar = 5;
float baz = 6.66f;
bar = foo<int>(bar);
baz = foo<float>(baz);
模板实例化机制根据之前定义的模板创建如下函数:
int foo(int v)
return -v;
float foo(float v)
return -v;
但是,当我们有一个模板类时,这个类可以有根本不使用依赖类型的函数:
template <typename T> class Foo
Foo() : mistery(0), value(0) ; // We're using the dependant type.
AddMistery() ++mistery; ; // We are not using the dependant type.
int mistery;
T value;
;
我首先想到AddMistery
方法可以放在cpp文件中,因为这个方法没有使用依赖类型,但是当我尝试它时,链接失败。这会儿我一记耳光,想起模板类的不同实例不是同一个类。因此,当链接器在执行它的工作时,它会查找 AddMistery
方法的主体,但没有找到它,因为 ir 被放入了 cpp 文件中:
// Foo.h
template <typename T> class Foo
Foo() : mistery(0), value(0) ; // We're using the dependant type.
AddMistery(); // We are not using the dependant type.
int mistery;
T value;
;
// Foo.cpp
#include "Foo.h"
template <typename T> Foo<T>::AddMistery()
++mistery;
// Main.cpp
#include "Foo.h"
int main(int argc, char **argv)
Foo<int> i;
Foo<float> f;
i.AddMistery(); // Link Error, where's the Foo<int>::AddMistery body?
f.AddMistery(); // Link Error, where's the Foo<float>::AddMistery body?
return 0;
;
所以,最后,问题来了:有一种方法可以在头文件和 cpp 文件之间拆分模板类,将所有非类型依赖方法的主体移动到 cpp,而不是将所有方法主体保留在头文件中文件?
【问题讨论】:
如果模板只在一个 .cpp 文件中使用过,则该模板可以进入该 .cpp 文件中,否则它需要在标题中。 我知道,模板必须放在同一个编译单元,但这不是问题;) 好的 - 我想我不明白这个问题 - 也许你可以澄清一下? 【参考方案1】:简短的回答是否定的,因为类模板不是类,除非您使用特定模板参数对其进行实例化。所以没有Foo::AddMystery()
可以实现。
这样想:成员函数知道依赖类型,因为它们有一个隐式的第一个参数,它是指向它们类的对象的指针。所以
Foo<int> f;
f.AddMistery();
等价于
Foo<int> f;
Foo<int>::AddMistery(&f);
如果您有特定类型的模板实例化,那么您可以在.cpp
文件中实现Foo<int>::AddMistery
,但这与不需要正文中的模板参数。
【讨论】:
【参考方案2】:除非您打算将模板仅用于有限的知名类型集,否则这是不可能的,例如int
、short
和 double
。在这种情况下,您可以使用显式实例化并将模板函数定义放在.cpp
文件中。
【讨论】:
以上是关于链接模板类函数的主要内容,如果未能解决你的问题,请参考以下文章