pen*_*ope 3 c++ templates codeblocks header-files
我知道 C++ 模板函数的定义必须放在头文件中。然而,出于提高我正在制作的(可能)大型库的可读性和结构的原因,我将声明与实现分开,放入“模拟”标头(其中#include实现文件,非常类似于这种文件结构)。请注意,我是否知道模板化函数的实现必须在编译时包含在内,并且我正在这样做。
简而言之,当我将非模板化函数声明添加到实现文件中时,出现“多重定义”错误。下面是带有示例的长解释。
\n\n当“模拟”头文件+实现文件对仅包含模板化函数的声明/实现对时,一切正常。当我仅在实现文件中添加新模板化函数的实现时,它也可以正常工作。
\n\n工作示例(当我想使用此功能时我会这样做)#include "algo.h":main.cpp
“模拟”头文件 algo.h :
\n\n#ifndef ALGO_H\n#define ALGO_H\n\nnamespace fl{\n template <typename Compare>\n void algo(.. non-templated args .., Compare order = std::less<int>());\n}\n\n#include "tpp/algo.cpp"\n\n#endif // ALGO_H\nRun Code Online (Sandbox Code Playgroud)\n\n实现文件 tpp/algo.cpp : (目前只是algo.tpp )
\n注意:使用该tpp/.cpp文件是在初始版本中,现在我使用每个@\xcf\x80\xce\xac\xce\xbd\xcf 的.tpp文件\x84\xce\xb1 \xe1\xbf\xa5\xce\xb5\xe1\xbf\x96 \的建议,解释在最后。
#ifndef TPP_ALGO\n#define TPP_ALGO\n\n#include "../algo.h"\n\nnamespace fl{\n\n template <typename Compare>\n void subFunctionality(Compare order, .. args ..){ /* impl */ }\n\n template <typename Compare>\n void algo(.. non-templated args .., Compare order){\n subFunctionality(order, .. args ..);\n // implementation\n }\n}\n\n#endif // TPP_ALGO\nRun Code Online (Sandbox Code Playgroud)\n\n当我在实现文件中添加非模板化函数实现时,问题就出现了。tpp/algo.cpp 的(非工作)示例(当前只是algo.tpp)(使用相同的algo.h):
\n\n#ifndef TPP_ALGO\n#define TPP_ALGO\n\n#include "../algo.h"\n\nnamespace fl{\n\n template <typename Compare>\n void subFunctionality(Compare order, .. args ..){ /* impl */ }\n\n void moreSubFun(.. args ..) { /* impl */ }\n\n template <typename Compare>\n void algo( .. non-templated args ..., Compare order){\n subFunctionality(order, .. args ..);\n moreSubFun(.. args ..);\n // more stuff\n }\n}\n\n#endif // TPP_ALGO\nRun Code Online (Sandbox Code Playgroud)\n\n我收到“多重定义”错误(来自我将其包含在 中的位置main.cpp),如下所示:
obj/Release/main.o In function `fl::moreSubFun(...)\':\nmain.cpp multiple definitions of `fl::moreSubFun(..)\'\nobj/Release/../tpp/algo.o:algo.cpp first defined here\nRun Code Online (Sandbox Code Playgroud)\n\n为什么这种情况只发生在非模板化函数上,而它对于模板化函数却可以正常工作,更重要的是,我该如何解决这个问题?
\n\n我环顾四周,找不到任何有用的东西:(理想情况下,我正在寻找尽可能接近我自己的文件结构的东西(但我会采取任何有效的东西,同时仍然使用一些分离“mock” .h+ tpp/.cpp)。我是否必须将额外的子功能放入单独的非模板文件对中.h/.cpp,或者是否有其他解决方案?(理想情况下,最终用户不应看到子功能) 。
inline我不愿意在定义时使用,fl::moreSubFunc(..)因为函数相当大(并且我被教导inline最好只与小函数一起使用)。这确实解决了问题,但我正在寻找是否有不同的解决方案。
我正在工作Code::Blocks,使用gcc version 4.7.2. tpp/.cpp这是我的实现文件是(扩展名)的最初原因.cpp,因为Code::Blocks默认情况下不支持它。根据@\xcf\x80\xce\xac\xce\xbd\xcf\x84\xce\xb1 \xe1\xbf\xa5\xce\xb5\xe1\xbf\x96 \ 的建议(往下看)。
后期编辑(在我教找到解决方案后)我教了@\xcf\x80\xce\xac\xce\xbd\xcf\x84\xce\xb1 \xe1\xbf\xa5\xce\xb5\xe1\xbf\x96 \的回答解决了问题。我调整Code::Blocks为接受.tpp文件(将其视为头文件或源文件)。最初,这个解决方案是有效的。
但是,只有当algo.h文件仅包含在另一个文件中时,此解决方案才有效:当我仅将其包含在main.cpp中时。然而,一旦我尝试将其包含在另一个使用这些算法(除了main.cpp之外)的源文件(例如algo2.cpp )中,多重定义问题又回来了。
\n\n最重要的是,只要我将 algo.h 包含在多个文件中,问题仍然存在,并且我仍在寻找解决方案。
\n出现问题是因为函数模板在链接时的处理方式与“普通”自由函数不同。函数必须遵守单一定义规则(ODR);也就是说,它们必须在不超过一个翻译单元中定义。否则,当您到达链接时间时,您最终会遇到多个定义错误,如您引用的错误。同样的规则也适用于一般的类、类型和对象。
这似乎完全排除了模板的使用;它们必须完全包含在使用它们的每个翻译单元中。然而,ODR 对少数情况进行了例外处理。引用维基百科:
有些东西,比如类型、模板和外部内联函数,可以在多个翻译单元中定义。对于给定实体,每个定义必须相同。不同翻译单元中的非外部对象和函数是不同的实体,即使它们的名称和类型相同。
这就是为什么您不会在模板函数中遇到多个定义错误。在链接时,链接器找到重复的符号定义并删除所有重复项(只要它们全部相等;否则,这将是一个错误)。因此,您的程序可以成功链接到每个所需符号的精确定义。
对于您的情况,出现问题是因为您在多个翻译单元(.cpp包含文件的任何位置)中包含非模板函数。有几种方法可以解决这个问题:
如果模板函数是类的一部分,您也可以将非模板函数移至该类中。这会将其置于所属模板类的符号重复数据删除保护伞下。
将函数标记为内联。
将非模板函数分解到另一个.cpp文件中,然后单独编译。这将是唯一容纳他们的翻译单位。