MyMSDN

MyMSDN记录开发新知道

关于C++ Template分离头文件和定义所产生的错误

编译错误

如图所示的代码出现了如图所示的错误,谁能解释一下是为什么呢?

虽然在最后include进了cpp文件,而且这种做法也在C++ Primer中也是正确的(难道是标准和现实的差距?)。将代码稍微变动,并将cpp部分的内容移到.h文件中的include位置即可正确编译。

编译正确

posted on 2009-02-22 06:05 volnet 阅读(4221) 评论(20)  编辑 收藏 引用

评论

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 09:12 huoxd

我记着这是个老问题了,的确不少的参考书中这么说过,但是要注意两点:
1.这样的分离只是文件层面的分离,并非是传统的模块之间只见接口,不见实现的分离,做为没用动态特性的静态语言,C++把模板的实现封装成二进制是不可能的,这种编程技巧只是为了让代码浏览起来感觉更规范.
2.不同的编译器对模板的实现还没有完全按照标准来支持,所以产生错误了不奇怪.  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 09:14 huoxd

是"没有动态特性"的,打错了,不好意思  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 12:04 空明流转

在源代码级别,模板是可以有一定程度的分离的.

我举个例子

//lib.h
template <class T> const T& return_itself(const T& val);

//lib.cpp
template <class T> const T& return_itself(const T& val){ return val; }
void instantiate_return_itself(){
//this is not executing factually.
return_itself((int)0);
}

//app.cpp
#include "lib.h"

int main(){
return_itself((int)0); // OK
return_itself(0.0f); // no compiler error happens but some link errors
}  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 12:37 huoxd

楼上说的是模板函数,的确可以分离,但模板类就不太容易了  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 18:23 Dancefire

楼主,你的问题其实很简单。

你是不是把foo.cpp也放进Visual C++的项目里了?如果是的话,这样会导致foo.cpp的编译,这个编译会导致T Foo<T>::GetInstance(void)被编译实现。当继续编译main.cpp的时候,就会报告,T Foo<T>::GetInstance(void)已经有一个实例了。

解决办法很简单,把foo.cpp移出工程就可以了。只要物理上foo.h的同目录存在foo.cpp这个文件就可以了。因为foo.cpp根本没必要去编译。甚至我都不建议你称其为foo.cpp,不如叫什么foo_impl.hpp之类的文件名更合理些,这样即使这个文件在工程里面也不回导致被编译。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 19:36 chujun

Foo.cpp里改成:
#ifndef FOO_H_
#include "foo.h"
template<typename T> T Foo<T>::GetInstance() {
return instance;
}
#endif
可以试一下...  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 20:57 yindf

Dancefire 的答案是对的,如果你自己写makefile的话,肯定不能把foo.cpp编译成foo.obj。

书上没有说这一点,但是你的IDE自动帮你makefile了,所以有些时候,自动化也有不好的地方呀。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 22:26 volnet

@Dancefire
的确,把foo.cpp移出项目外的话就可以顺利编译并执行了!
但是在你的回答中,为什么会提到“当继续编译main.cpp的时候……”,这是为什么呢?为什么非模板类型就可以?  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 23:11 空明流转

非模板类型的应该也是不可以的。
还有就是,不仅仅是模板函数,模板类一样可以。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-22 23:15 volnet

@空明流转
我说的可以是指在h中声明,在cpp中定义,这显然是可以的(也是标准的做法)
模板函数和模板类的确都存在如本文所述的问题,并且用Dancefire的方法,或者使用全部写在.h文件中的方式,都是可以的。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 00:49 Dancefire

@volnet
呵呵,非模板类型的函数定义我们也不会需要在foo.h中include foo.cpp啊:)

在楼主的例子里面为了能够让定义和声明分开,将声明放到了foo.h中,而定义放到了foo.cpp中,这和非模板类型的函数是一样的。但是可惜这么做是无法通过的,因为模板类型函数不能够(由于没有export支持)单独编译。为了让编译通过,楼主将foo.cpp给include进了foo.h,这样实际上是将两个文件整合成一个文件了。这样编译就没有问题了,但是得小心需要把foo.cpp分离出项目,因为它不可以被编译;或者将其扩展名从.cpp改为.hpp。

实在是不推荐楼主这么分开的写,说实话这算不上是什么标准的做法,而且这样并没有太大的意义。如果非要分开,可以将定义后缀到声明后面,在一个文件里。但是分开确实没太大意义。可以研读一下boost里面的做法。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 00:54 volnet

@Dancefire
原来你们说的是include foo.cpp

分开有一个好处就是可以成套地替换吧,虽然通常我们不这么做,但是却从语法上支持了这么做。如果可以当然好了,不行的话肯定是没办法的。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 00:57 volnet

@Dancefire
boost在C++中的地位是什么呢?一个工业库?一个泛型标准?一个开源范例?它对C++学习有什么好处呢?  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 01:17 Dancefire

@volnet
Boost可以称其为是一套准标准库。它项目建立的目的之一就是为未来的C++标准库提供候选方案,目前已经有将近十个Boost库成功的成为了C++标准预案。

它的优势很多,首先是代码使用现代C++的语法,因此namespace, 异常, 模板之类的C++特性会被充分挖掘利用,代码从设计、实现到文档都具有了相当高的水准。另外,由于它使用的是标准C++语法编写,因此它的可移植性非常的好。当然,针对一些存在问题的编译器,它也会进行相应的调整以尽量支持。

Boost这种优良的库,涵盖的领域很广,可以说是标准库很好的补充。另外绝大多数Boost库都不需要编译链接,大部分的Boost库仅仅include头文件即可工作。我看到国内很多人提到Boost的时候说它比较难以编译安装云云。其实没必要编译,绝大多数的库仅仅是由头文件组成的,只要include进来就可以用了。

Boost是C++强有力的工具,学习C++,除了标准语法和STL外,Boost是必须熟悉的,否则,工程上很有可能会做一些Boost已经实现很久的东西,除了重复开发外,而且你的代码的质量和可持续性比Boost差很远,造成项目质量的下降。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 01:22 volnet

@Dancefire
谢谢你对Boost做了详细的介绍。
那么,学习Boost库需要有哪些准备工作?(假设从初学者开始)学习Boost库又有哪些方法或者经典的做法呢?(比如什么书,或者什么文档)  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 13:29 maosher

foo.h里面最下面倒数第二行

的#include   回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 13:34 volnet

@maosher
怎么了?  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-02-23 16:22 陈梓瀚(vczh)

template特化是链接期不能解决的问题,因此必须放进.h,不要使用别扭的技巧来分离。其实直接写在一个class{}里面反而漂亮得多。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2009-03-02 11:20 xcj

简单的问题。把foo.cpp中#include "foo.h"那行删除掉应该就没问题了。  回复  更多评论   

# re: 关于C++ Template分离头文件和定义所产生的错误 2012-01-02 20:27 wzm

.cpp 的模板前面加个 export试试  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


特殊功能