我知道必须将C++模板化函数的定义放在头文件中。但是,由于提高了我正在制作的(可能是)大库的可读性和结构的原因,我将声明与实现分开,放入“模拟” header (该#include
实现文件,与文件的this structure类似)。请注意,我知道模板功能的实现必须在编译时包括在中,而我正在这样做。
简而言之,将非模板函数声明添加到实现文件中时,出现“多个定义”错误。以下是带有示例的详细说明。
当一对“模拟”头文件+实现文件仅包含模板函数的声明/实现对时,一切正常。当我仅在实现文件中添加新模板功能的实现时,它也可以正常工作。
工作示例(当我想使用此功能时,可以在#include "algo.h"
中输入main.cpp
):
“模拟”头文件 algo.h :
#ifndef ALGO_H
#define ALGO_H
namespace fl{
template <typename Compare>
void algo(.. non-templated args .., Compare order = std::less<int>());
}
#include "tpp/algo.cpp"
#endif // ALGO_H
实现文件 tpp / algo.cpp :(当前只是algo.tpp)
注意:最初版本使用
tpp/.cpp
文件,现在根据@πάντα ῥεῖ的建议和解释,我现在使用.tpp
文件。#ifndef TPP_ALGO
#define TPP_ALGO
#include "../algo.h"
namespace fl{
template <typename Compare>
void subFunctionality(Compare order, .. args ..){ /* impl */ }
template <typename Compare>
void algo(.. non-templated args .., Compare order){
subFunctionality(order, .. args ..);
// implementation
}
}
#endif // TPP_ALGO
当我在实现文件中添加非模板函数实现时,就会出现问题。 tpp / algo.cpp(目前只是algo.tpp)的(非工作状态)示例(使用相同的algo.h):
#ifndef TPP_ALGO
#define TPP_ALGO
#include "../algo.h"
namespace fl{
template <typename Compare>
void subFunctionality(Compare order, .. args ..){ /* impl */ }
void moreSubFun(.. args ..) { /* impl */ }
template <typename Compare>
void algo( .. non-templated args ..., Compare order){
subFunctionality(order, .. args ..);
moreSubFun(.. args ..);
// more stuff
}
}
#endif // TPP_ALGO
我收到了“多个定义” 错误(从我在
main.cpp
中包括它的位置),如下所示:obj/Release/main.o In function `fl::moreSubFun(...)':
main.cpp multiple definitions of `fl::moreSubFun(..)'
obj/Release/../tpp/algo.o:algo.cpp first defined here
为什么这仅会发生在非模板函数上,而对于模板化也可以正常工作,更重要的是,我如何解决此问题?
我到处都是,但找不到有用的东西:(理想情况下,我正在寻找尽可能接近自己的文件结构的东西(但是我会采取一切可行的措施,同时仍将某些部分分隔为“模拟” “
.h
+ tpp/.cpp
)。我是否必须将其他子功能分解为单独的,没有模板的一对.h/.cpp
文件,还是有其他解决方案?(理想情况下,最终用户应该看不到这些子功能) )。我不愿意在定义
inline
时使用fl::moreSubFunc(..)
,因为该函数相当大(而且我被告知inline
理想情况下仅应与小型函数一起使用)。确实可以解决问题,但是我正在寻找是否有其他解决方案。我正在使用
Code::Blocks
在gcc version 4.7.2
中工作。这是我的实现文件是tpp/.cpp
(扩展名.cpp
)的最初原因,因为Code::Blocks
默认情况下不支持它。在@πάντα ῥεῖ的建议下(在下面看),在当前实现中对此进行了更改。后期编辑(在我教了解决方案之后,我教了@πάντα ῥεῖ's answer解决了这个问题。我调整了
Code::Blocks
以接受.tpp
文件(将其视为头文件或源文件)。最初,此解决方案有效。但是,此解决方案仅在algo.h文件仅包含在另一个文件中时有效:当我仅在main.cpp中包含它时。但是,一旦我尝试将其包含在将使用这些算法(除main.cpp之外)的另一个源文件(例如algo2.cpp)中,多定义问题又回来了。
底线,只要我将algo.h包含在多个文件中,问题仍然存在,我仍在寻找解决方案。
最佳答案
发生您的问题的原因是,链接时的功能模板与“普通”免费功能的处理方式不同。函数必须遵循One Definition Rule (ODR);也就是说,它们的定义不得超过一个翻译单位。否则,当您链接时间时,最终会遇到多个定义错误,例如您引用的错误。相同的规则通常也适用于类,类型和对象。
这似乎完全排除了模板的使用;它们必须完全包含在使用它们的每个翻译单元中。但是,ODR在某些情况下是一个异常(exception)。引用维基百科:
Some things, like types, templates, and extern inline functions, can be defined in more than one translation unit. For a given entity, each definition must be the same. Non-extern objects and functions in different translation units are different entities, even if their names and types are the same.
这就是为什么您不会在模板函数中遇到多个定义错误的原因。在链接时,链接程序会找到重复的符号定义,并删除所有重复的符号(只要它们都相等即可;否则,将是错误的)。因此,您的程序将成功链接每个所需符号的确切定义。
对于您的情况,发生问题是因为您在多个翻译单元(包括
.cpp
文件的所有位置)中都包含非模板函数。有几种解决方法:.cpp
文件,然后分别编译。那将是容纳它们的唯一翻译单位。 关于c++ - 使用(mock)头文件作为模板时的“Multiple definition”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25139535/