使用(模拟)模板头文件时的“多重定义”

pen*_*ope 3 c++ templates codeblocks header-files

我知道 C++ 模板函数的定义必须放在头文件中。然而,出于提高我正在制作的(可能)大型库的可读性和结构的原因,我将声明与实现分开,放入“模拟”标头(其中#include实现文件,非常类似于这种文件结构)。请注意,我是否知道模板化函数的实现必须在编译时包含在内,并且我正在这样做。

\n\n

简而言之,当我将非模板化函数声明添加到实现文件中时,出现“多重定义”错误。下面是带有示例的长解释。

\n\n

当“模拟”头文件+实现文件对仅包含模板化函数的声明/实现对时,一切正常。当我仅在实现文件中添加新模板化函数的实现时,它也可以正常工作。

\n\n

工作示例(当我想使用此功能时我会这样做)#include "algo.h"main.cpp

\n\n

“模拟”头文件 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\n
Run 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 \的建议,解释在最后。

\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    template <typename Compare>\n    void algo(.. non-templated args .., Compare order){\n         subFunctionality(order, .. args ..);\n        // implementation\n    }\n}\n\n#endif // TPP_ALGO\n
Run 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\n
Run Code Online (Sandbox Code Playgroud)\n\n

我收到“多重定义”错误(来自我将其包含在 中的位置main.cpp),如下所示:

\n\n
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\n
Run Code Online (Sandbox Code Playgroud)\n\n

为什么这种情况只发生在非模板化函数上,而它对于模板化函数却可以正常工作,更重要的是,我该如何解决这个问题?

\n\n

我环顾四周,找不到任何有用的东西:(理想情况下,我正在寻找尽可能接近我自己的文件结构的东西(但我会采取任何有效的东西,同时仍然使用一些分离“mock” .h+ tpp/.cpp)。我是否必须将额外的子功能放入单独的非模板文件对中.h/.cpp,或者是否有其他解决方案?(理想情况下,最终用户不应看到子功能) 。

\n\n

inline我不愿意在定义时使用,fl::moreSubFunc(..)因为函数相当大(并且我被教导inline最好只与小函数一起使用)。这确实解决了问题,但我正在寻找是否有不同的解决方案。

\n\n

我正在工作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 \ 的建议(往下看)。

\n\n
\n\n

后期编辑(在我教找到解决方案后)我教了@\xcf\x80\xce\xac\xce\xbd\xcf\x84\xce\xb1 \xe1\xbf\xa5\xce\xb5\xe1\xbf\x96 \的回答解决了问题。我调整Code::Blocks为接受.tpp文件(将其视为头文件文件)。最初,这个解决方案是有效的。

\n\n

但是,只有当algo.h文件仅包含在另一个文件中时,此解决方案才有效:当我仅将其包含在main.cpp中时。然而,一旦我尝试将其包含在另一个使用这些算法(除了main.cpp之外)的源文件(例如algo2.cpp )中,多重定义问题又回来了。

\n\n

最重要的是,只要我将 algo.h 包含多个文件中,问题仍然存在,并且我仍在寻找解决方案

\n

Jas*_*n R 5

出现问题是因为函数模板在链接时的处理方式与“普通”自由函数不同。函数必须遵守单一定义规则(ODR);也就是说,它们必须在不超过一个翻译单元中定义。否则,当您到达链接时间时,您最终会遇到多个定义错误,如您引用的错误。同样的规则也适用于一般的类、类型和对象。

这似乎完全排除了模板的使用;它们必须完全包含在使用它们的每个翻译单元中。然而,ODR 对少数情况进行了例外处理。引用维基百科:

有些东西,比如类型、模板和外部内联函数,可以在多个翻译单元中定义。对于给定实体,每个定义必须相同。不同翻译单元中的非外部对象和函数是不同的实体,即使它们的名称和类型相同。

这就是为什么您不会在模板函数中遇到多个定义错误。在链接时,链接器找到重复的符号定义并删除所有重复项(只要它们全部相等;否则,这将是一个错误)。因此,您的程序可以成功链接到每个所需符号的精确定义。

对于您的情况,出现问题是因为您在多个翻译单元(.cpp包含文件的任何位置)中包含非模板函数。有几种方法可以解决这个问题:

  1. 如果模板函数是类的一部分,您也可以将非模板函数移至该类中。这会将其置于所属模板类的符号重复数据删除保护伞下。

  2. 将函数标记为内联。

  3. 将非模板函数分解到另一个.cpp文件中,然后单独编译。这将是唯一容纳他们的翻译单位。