2

我有一个 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为空(它将用于发布版本)并且不为调用生成任何代码,我会有将它作为参数在课堂上的任何地方传递。

可以做到吗?

4

3 回答 3

1

好吧,我重新创造了一切,

这个错误在这里undefined reference to void C::DoThis<&(LogIt(char const*, ...))>()解释

现在,如果您确实#include "C.cpp"在上面提到,这将导致

undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()

所以修复:

template <LogFunction L>
void C::DoThat()  //Notice :: used here
{
    L("DoThat!");
}

一切都遵守并执行!

于 2013-08-02T14:17:28.223 回答
0

您需要将模板定义放在与其声明的位置相同的位置。这意味着您需要将 LogIt 函数放在头文件中声明的位置。到目前为止,我们还不能像这样显式地分离模板声明和它的定义。

于 2013-08-02T14:25:35.980 回答
0

这是因为您的模板在编译器应该实例化它们的地方是不可见的,因为您只有 Ch 中的声明和 Cc 中的定义

将模板定义移动到标题或强制在抄送中实例化您必须为此在抄送中提供 LogIt 声明。

于 2013-08-02T14:16:41.147 回答