2009年7月20日星期一

又被C++编译器给郁闷了~

继续我那个该死的 Log 工具,然后为了做刚写好的 C++ 反射模块的 Unit Test,于是就写了一个 C++ 代码来生成实验数据。
为了测试的普遍性,我写了几个随机函数,用来生成各种类型的数据。
然后由于还有数组,于是就像写一个随机生成数组内容的函数。
然后很开心的写了一个模板函数,传入数组,数组长度,以及数组元素的随机生成函数。

函数的 Definition 大概是这样的:

template<class T>
void RndArray(T target[], int length, T (*RndT)())
{
T* pEnd = target + length;
for(T* fo = target; fo< pEnd; fo++)
{
*fo = RndT();
}
}

把这段代码写在 util.cpp 里后,很开心的在头文件里写了一个 declaration:
大概是这样的:
template<class T>
void RndArray(T target[], int length, T (*RndT)());

然后编译~一切OK~

然后为了测试一下,于是在 Main 函数里写了这么一段:

#include "stdafx.h"

using namespace System;
using namespace util;

int main(array<System::String ^> ^args)
{
InitializeUtil();

INT temp[10];
RndArray<INT>(temp,10,RndINT);
for(int fo =0;fo<10;fo++)
Console::WriteLine("[{0}] = {1}",fo,temp[fo]);
Console::ReadKey();
return 0;
}


再编译~
Error~

估计是模板实例化的时候出问题,开始倒腾那段模板代码,倒腾了10分钟还是不行,于是仔细看看错误消息:

Error 1 error LNK2028: unresolved token (0A00000D) "void __cdecl util::RndArray<int>(int * const,int,int (__cdecl*)(void))" (??$RndArray@H@util@@$$FYAXQAHHP6AHXZ@Z) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z) EntityDataGenerator.obj EntityDataGenerator

Error 2 error LNK2019: unresolved external symbol "void __cdecl util::RndArray<int>(int * const,int,int (__cdecl*)(void))" (??$RndArray@H@util@@$$FYAXQAHHP6AHXZ@Z) referenced in function "int __clrcall main(cli::array<class System::String ^ >^)" (?main@@$$HYMHP$01AP$AAVString@System@@@Z) EntityDataGenerator.obj EntityDataGenerator

发现是 Link 时出错,说明代码不是 definition 的问题,估计会是 declaration 的问题,于是倒腾头文件:调整 declaration 的顺序,修改命名空间,检查 头文件引用……

倒腾了半个小时还是不行~MSDN 上也没有任何相关的内容~

思考了一下,发现其他的正常的函数是一切OK的,问题就处在模板上~
模板函数如果不做模板实例化就什么也没有,只有实例化以后才会存在。因此如果模板函数更接近于一种 declaration 而不是 definition, 于是把 .cpp 的内容全部挪到 .h 里~

编译~执行~一切正常~

于是去仔细读了读模板的规范,发现在最后面有这么几段话:

From the point of view of the compiler, templates are not normal functions or classes. They are compiled on demand, meaning that the code of a template function is not compiled until an instantiation with specific template arguments is required. At that moment, when an instantiation is required, the compiler generates a function specifically for those arguments from the template.

Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.

Since no code is generated until a template is instantiated when required, compilers are prepared to allow the inclusion more than once of the same template file with both declarations and definitions in a project without generating linkage errors.

就因为这个该死的原因,让我对这么10行不到的代码郁闷了1个多小时~学之不精害死人啊~

TimNew
------------
Release you passion
To Realize you potential
---------------------------------
Tip Of the Day:
Marcus Garvey  - "With confidence, you have won before you have started."

Posted via email from timnew's posterous

没有评论:

发表评论