2

I have an Apache module (.so) that contains a class I'm trying to completely decouple from Apache itself. The biggest source of frustration is the debug logging. I want to be able to pass the logging function to the class through the template parameters. I can get the proof of concept to work fine when everything is in the same translation unit, but it falls over once they're not because the logging function is an 'undefined reference':

/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

This also happens when Apache tries to load the module containing the class. The code below reproduces the problem:

// 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!");
}

I'd prefer not to have to resort to having the function passed as a function parameter, i.e.

template <typename F>
void C::DoThis(F f)
{
    f("DoThis!");
}

because I'd like to structure the code in such a way that the compiler is able to figure out if the body of LogIt is empty (which it will be for Release builds) and not generate any code for the call, and I'd have to pass it as an argument everywhere in the class.

Can it be done?

James
  • 9,064
  • 3
  • 31
  • 49

3 Answers3

1

Okay I recreated everything,

This error undefined reference to void C::DoThis<&(LogIt(char const*, ...))>() is explained here

Now if you do #include "C.cpp" referring above, this will lead to

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

So fix:

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

and everything complies and execute !

Community
  • 1
  • 1
P0W
  • 46,614
  • 9
  • 72
  • 119
0

This is because you have your templates invisible at the point where compiler is supposed to instantiate them as you only have a declaration in C.h and a definition in C.c.

Either move template definitions to header or force instantiation in C.c. You will have to provide LogIt declaration in C.c for that.

Tomek
  • 4,554
  • 1
  • 19
  • 19
0

You need to put template definition in the same as the place where its declared. So that means you need to put your LogIt function where it was declared in the header file. As of right now, we are not able to explicitly separate template declaration and its definition like that.

dchhetri
  • 6,926
  • 4
  • 43
  • 56