使用任意函数作为模板参数参数

时间:2013-08-02 12:56:46

标签: c++ templates

我有一个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的主体是否为空(它将用于发布版本)并且不生成任何代码这个电话,我必须在课堂上的任何地方作为论据传递它。

可以吗?

3 个答案:

答案 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函数放在头文件中声明的位置。截至目前,我们无法明确区分模板声明及其定义。