MyMSDN记录开发新知道
如图所示的代码出现了如图所示的错误,谁能解释一下是为什么呢?
虽然在最后include进了cpp文件,而且这种做法也在C++ Primer中也是正确的(难道是标准和现实的差距?)。将代码稍微变动,并将cpp部分的内容移到.h文件中的include位置即可正确编译。
posted on 2009-02-22 06:05 volnet 阅读(4293) 评论(20) 编辑 收藏 引用
我记着这是个老问题了,的确不少的参考书中这么说过,但是要注意两点: 1.这样的分离只是文件层面的分离,并非是传统的模块之间只见接口,不见实现的分离,做为没用动态特性的静态语言,C++把模板的实现封装成二进制是不可能的,这种编程技巧只是为了让代码浏览起来感觉更规范. 2.不同的编译器对模板的实现还没有完全按照标准来支持,所以产生错误了不奇怪. 回复 更多评论
是"没有动态特性"的,打错了,不好意思 回复 更多评论
在源代码级别,模板是可以有一定程度的分离的.我举个例子//lib.htemplate <class T> const T& return_itself(const T& val);//lib.cpptemplate <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} 回复 更多评论
楼上说的是模板函数,的确可以分离,但模板类就不太容易了 回复 更多评论
楼主,你的问题其实很简单。 你是不是把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之类的文件名更合理些,这样即使这个文件在工程里面也不回导致被编译。 回复 更多评论
Foo.cpp里改成:#ifndef FOO_H_#include "foo.h"template<typename T> T Foo<T>::GetInstance() { return instance;}#endif可以试一下... 回复 更多评论
Dancefire 的答案是对的,如果你自己写makefile的话,肯定不能把foo.cpp编译成foo.obj。 书上没有说这一点,但是你的IDE自动帮你makefile了,所以有些时候,自动化也有不好的地方呀。 回复 更多评论
@Dancefire 的确,把foo.cpp移出项目外的话就可以顺利编译并执行了! 但是在你的回答中,为什么会提到“当继续编译main.cpp的时候……”,这是为什么呢?为什么非模板类型就可以? 回复 更多评论
非模板类型的应该也是不可以的。还有就是,不仅仅是模板函数,模板类一样可以。 回复 更多评论
@空明流转 我说的可以是指在h中声明,在cpp中定义,这显然是可以的(也是标准的做法) 模板函数和模板类的确都存在如本文所述的问题,并且用Dancefire的方法,或者使用全部写在.h文件中的方式,都是可以的。 回复 更多评论
@volnet呵呵,非模板类型的函数定义我们也不会需要在foo.h中include foo.cpp啊:)在楼主的例子里面为了能够让定义和声明分开,将声明放到了foo.h中,而定义放到了foo.cpp中,这和非模板类型的函数是一样的。但是可惜这么做是无法通过的,因为模板类型函数不能够(由于没有export支持)单独编译。为了让编译通过,楼主将foo.cpp给include进了foo.h,这样实际上是将两个文件整合成一个文件了。这样编译就没有问题了,但是得小心需要把foo.cpp分离出项目,因为它不可以被编译;或者将其扩展名从.cpp改为.hpp。实在是不推荐楼主这么分开的写,说实话这算不上是什么标准的做法,而且这样并没有太大的意义。如果非要分开,可以将定义后缀到声明后面,在一个文件里。但是分开确实没太大意义。可以研读一下boost里面的做法。 回复 更多评论
@Dancefire 原来你们说的是include foo.cpp 分开有一个好处就是可以成套地替换吧,虽然通常我们不这么做,但是却从语法上支持了这么做。如果可以当然好了,不行的话肯定是没办法的。 回复 更多评论
@Dancefire boost在C++中的地位是什么呢?一个工业库?一个泛型标准?一个开源范例?它对C++学习有什么好处呢? 回复 更多评论
@volnetBoost可以称其为是一套准标准库。它项目建立的目的之一就是为未来的C++标准库提供候选方案,目前已经有将近十个Boost库成功的成为了C++标准预案。它的优势很多,首先是代码使用现代C++的语法,因此namespace, 异常, 模板之类的C++特性会被充分挖掘利用,代码从设计、实现到文档都具有了相当高的水准。另外,由于它使用的是标准C++语法编写,因此它的可移植性非常的好。当然,针对一些存在问题的编译器,它也会进行相应的调整以尽量支持。Boost这种优良的库,涵盖的领域很广,可以说是标准库很好的补充。另外绝大多数Boost库都不需要编译链接,大部分的Boost库仅仅include头文件即可工作。我看到国内很多人提到Boost的时候说它比较难以编译安装云云。其实没必要编译,绝大多数的库仅仅是由头文件组成的,只要include进来就可以用了。Boost是C++强有力的工具,学习C++,除了标准语法和STL外,Boost是必须熟悉的,否则,工程上很有可能会做一些Boost已经实现很久的东西,除了重复开发外,而且你的代码的质量和可持续性比Boost差很远,造成项目质量的下降。 回复 更多评论
@Dancefire 谢谢你对Boost做了详细的介绍。 那么,学习Boost库需要有哪些准备工作?(假设从初学者开始)学习Boost库又有哪些方法或者经典的做法呢?(比如什么书,或者什么文档) 回复 更多评论
foo.h里面最下面倒数第二行 的#include 回复 更多评论
@maosher 怎么了? 回复 更多评论
template特化是链接期不能解决的问题,因此必须放进.h,不要使用别扭的技巧来分离。其实直接写在一个class{}里面反而漂亮得多。 回复 更多评论
简单的问题。把foo.cpp中#include "foo.h"那行删除掉应该就没问题了。 回复 更多评论
.cpp 的模板前面加个 export试试 回复 更多评论
Powered by: C++博客 Copyright © volnet