我在一个头文件里定义了声明了一个模版函数,如下
//Combination.h
#ifndef VECTOR_H
#define VECTOR_H
#include <vector>
#endif
template<class T> void Combination(T a[], int len, int index, int m, std::vector<T>& c);
CPP里定义
//Combination.cpp
#include "Combination.h"
using namespace std;
template<class T> void Combination(T a[], int len, int index, int m, vector<T>& c)
{
if(0 == m)
{
vector<T>::iterator iter = c.begin();
for(; iter != c.end(); ++iter)
{
cout<<*iter;
}
printf("\n");
return;
}
if(len == index)
return;
c.push_back(a[index]);
Combination(a, len, index + 1, m - 1, c);
c.pop_back();
Combination(a, len, index + 1, m, c);
}
main中调用
#include <iostream>
#include "Combination.h"
#ifndef VECTOR_H
#define VECTOR_H
#include <vector>
#endif
using namespace std;
void main()
{
int a[] = {1,2,3,4,5,6};
vector<int> c;
Combination(a, sizeof(a) / sizeof(int), 0, 3, c);
system("pause");
return;
}
编译连接时提示以下错误
错误 1 error LNK2019: 无法解析的外部符号 "void __cdecl Combination<int>(int * const,int,int,int,class std::vector<int,class std::allocator<int> > &)" (??$Combination@H@@YAXQAHHHHAAV?$vector@HV?$allocator@H@std@@@std@@@Z),该符号在函数 _main 中被引用 main.obj CppTest
错误 2 fatal error LNK1120: 1 个无法解析的外部命令 D:\Documents\Visual Studio 2008\Projects\CppTest\Debug\CppTest.exe CppTest
但是,如果把Combination函数的定义直接放在main中,可以通过编译连接并正确运行。请问怎么解决,模版函数不能那样放在头文件中声明,CPP中定义吗
理解这个问题,需要一点编译原理的知识,在调用一个方法或者使用一个类的时候,本cpp作为一个独立的编译单元,可能并不知道某一个方法或者类型的符号是怎么样的,但是这时候不会出错,还是可以针对每个编译单元生成目标文件obj,之后针对没有找到的方法或者类型符号,链接器会在别的obj文件中寻找缺失的符号。
假设模版函数可以放在头文件中声明,CPP中定义,按照你的例子分析一下:
main中调用Combination(a, sizeof(a) / sizeof(int), 0, 3, c);,也就是类型Combination(int, int,int,int, vector<int>&);但是编译器并不知道Combination(int, int,int,int, vector<int>&);,因为这个类型并不在任何一个.h文件中,之后编译器会寄希望于链接器可以解决这个问题,也就是在Combination.cpp的编译目标文件Combination.obj中,但是Combination.obj也没有这个类型,它有的只是一个模板定义。
C++标准里规定: 当一个模板不被用到的时侯它就不该被实例化出来,Combination.cpp没有用到Combination(int, int,int,int, vector<int>&);,所以也就不会编译出来该符号,链接出错也就可以理解了。
感谢你的回答。
就是说,模版函数只能在使用它的编译单元中定义吗?
那如果同一个模版函数,我会在多个编译单元中使用到,难道要每个编译单元都要定义一次?
像STL里面的那些模版是怎么实现的?使用STL的时候,包含头文件就可以了啊
@粗暴的香蕉: 你应该去看一下STL的实现,都是在.h文件中完成的,同一个模板函数,在多个编译单元中使用,那么就在头文件中给出声明和实现,有一些编译器是提供export关键字支持分离式编译的,不过并不是所有的编译器都支持。
@Wang Hui: 谢谢你,明白了,我要学习的还有很多,赶快去看一下STL源码才行
将函数的实现放在。h文件中,。这个好像叫做分离编译什么的吧