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

Use arbitrary functions as template parameter arguments

本文关键字:参数 任意 函数      更新时间:2023-10-16

我有一个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的主体是否为空(对于Release构建,它将是空的),并且不为调用生成任何代码,并且我必须将其作为类中的任何地方的参数传递。

能做到吗?

好的,我重新创建了所有东西,

此错误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!");
}

一切都遵守并执行!

这是因为在编译器应该实例化模板的时候,模板是不可见的,因为你只有C.h中的声明和C.C.中的定义。

要么将模板定义移动到标头中,要么在C.C中强制实例化。为此,您必须在C.中提供LogIt声明。

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