我有一个Apache模块(.so),它包含一个我试图完全与Apache本身分离的类。最令人沮丧的是调试日志记录。我希望能够通过模板参数将日志记录功能传递给类。当所有内容都在同一个翻译单元中时,我可以使概念证明正常工作,但是一旦它们不存在就会失败,因为日志记录功能是一个'未定义的引用':
/tmp/ccPdPX2A.o: In function `main':
test.cpp:(.text+0x81): undefined reference to `void C::DoThis<&(LogIt(char const*, ...))>()'
collect2: ld returned 1 exit status
当Apache尝试加载包含该类的模块时,也会发生这种情况。 下面的代码重现了这个问题:
// main.cpp
#include <iostream>
#include "C.h"
void LogIt(const char*, ...)
{
std::cout << "GADZOOKS!\n";
}
int main(int argc, char* argv[])
{
C c;
c.DoThis<LogIt>();
}
// C.h
typedef void (*LogFunction)(const char*, ...);
class C
{
public:
template <LogFunction L>
void DoThis();
template <LogFunction L>
void DoThat();
};
// C.cpp
#include "C.h"
template <LogFunction L>
void C::DoThis()
{
L("DoThis!");
DoThat<L>();
}
template <LogFunction L>
void C::DoThat()
{
L("DoThat!");
}
我宁愿不必将函数作为函数参数传递,即
template <typename F>
void C::DoThis(F f)
{
f("DoThis!");
}
因为我想以这样的方式构造代码:编译器能够判断LogIt
的主体是否为空(它将用于发布版本)并且不生成任何代码这个电话,我必须在课堂上的任何地方作为论据传递它。
可以吗?
答案 0 :(得分:1)
好的,我重新创造了一切,
此错误undefined reference to void C::DoThis<&(LogIt(char const*, ...))>()
已解释为here
现在,如果你在上面提到#include "C.cpp"
,那么这将导致
undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()
所以修复:
template <LogFunction L>
void C::DoThat() //Notice :: used here
{
L("DoThat!");
}
并且一切都符合并执行!
答案 1 :(得分:0)
这是因为你的模板在编译器应该实例化时是不可见的,因为你只有C.h中的声明和C.c中的定义。
将模板定义移动到标题或强制实例化C.c.您必须在C.c中提供LogIt声明。
答案 2 :(得分:0)
您需要将模板定义与其声明的位置相同。这意味着您需要将LogIt函数放在头文件中声明的位置。截至目前,我们无法明确区分模板声明及其定义。