Templated function pointer as function argument

I'm having an issue with sending a function pointer to a non-static member function as an argument using templates.

Here are a two scenarios that don't generate compile errors but the last one (#3) gives a compile error.

Any insight on why this might be so would be appreciated.

Below are the code snippets that show the relevant lines of code for each scenario, that appear in the .h and .cpp files.
Note: PuzzleGUI is the actual class that the non-static member function pointer belongs to.

#1
.h:
void addOnMapChangeEvent( void (PuzzleGUI::*f)(char, char) );
.cpp:
void CharMapGUI::addOnMapChangeEvent( void (PuzzleGUI::*f)(char, char) ){}

#2
.h:
template<typename T>
void addOnMapChangeEvent( void (T::*f)(char, char) ){}
.cpp:

#3 (Does not compile)
.h:
template<typename T>
void addOnMapChangeEvent( void (T::*f)(char, char) );
.cpp:
template<typename T>
void CharMapGUI::addOnMapChangeEvent( void (T::*f)(char, char) ){}

The error message is of little use but here it is below.
1) error LNK2019: unresolved external symbol "public: void __thiscall CharMapGUI::addOnMapChangeEvent<class PuzzleGUI>(void (__thiscall PuzzleGUI::*)(char,char))" (??$addOnMapChangeEvent@VPuzzleGUI@@@CharMapGUI@@QAEXP8PuzzleGUI@@AEXDD@Z@Z) referenced in function "private: void __thiscall CryptoquoteGUI::initializeGame(void)" (?initializeGame@CryptoquoteGUI@@AAEXXZ)
2) fatal error LNK1120: 1 unresolved externals

For #3 error - It's the way you have split up the template function between the h file declaration and the definition in the cpp file.

#2 does not create an error because you have the function body in the h file.
My personal experience is unless I am building C++ library for ppl to use, I do not code C++ templates. I only use them cuz STL mandate me to do.

Having template code inside .h file is so "uncool" and I am still waiting for newer C++ compiler to allow us to split templatized code into .h and .cpp like their non-templatized cousins!

side qn, for #2, the method pointer can be a method of any class that returns void and takes in 2 char parameters right?

template<typename T>
void addOnMapChangeEvent( void (T::*f)(char, char) ){}

btw, can a template be split into a .h and .cpp file?
@sohguanh:

Rename the .cpp file to .inl or something, then #include it at the bottom of the header file. Problem solved.

@unregistered:

No, see my response to sohguanh.

for #2, the method pointer can be a method of any class that returns void and takes in 2 char parameters right?

template<typename T>
void addOnMapChangeEvent( void (T::*f)(char, char) ){}
Rename the .cpp file to .inl or something, then #include it at the bottom of the header file. Problem solved.


You mean something like say below ?

filename is mytest.h
#ifndef TEST
#define TEST
...
...
..
#include "mytest.nl"
#endif

But it only make the mytest.h look "cleaner", the code still go inside mytest.inl ? However I agree with this work-ard, the .h file look "cleaner" :P

Last edited on
Yes. mytest.cpp is just renamed to mytest.inl.

(btw, you'll be waiting for a very long time for C++ compilers to allow you to put template code in .cpp files. This
"feature" was supported by the export keyword which is being removed in C++0x.)


(btw, you'll be waiting for a very long time for C++ compilers to allow you to put template code in .cpp files. This
"feature" was supported by the export keyword which is being removed in C++0x.)


What take the compiler writer so long to come out with this neat feature of putting template code into .h and .cpp ?

I presume there is some technical difficulty in implementation ? Hmmm... maybe someone who work in a company that produce C++ compiler wanna shed some knowledge ? :P
Yes, there is.

If you put the template code in a .cpp file, what exactly can the compiler do when it compiles the .cpp? It can't
generate code, because it doesn't know the real types. Consider this simple example:

1
2
3
template< typename T >
T add( T a, T b )
{ return a + b; }


If this code were in a .cpp file, what instructions could the compiler generate? How many different ways will this
function actually be called in the code?

If T is int, then a + b can generate an ADD instruction.
If T is float, then a + b must generate FADD (floating point add) instruction.
If T is std::string, then a + b must call operator+ on std::string.

Etc, etc.

The point is that the compiler can't generate code for the function until it knows what type T is. And if the
function is called with many different T's in the program, then the compiler must generate many different
versions of code for the same function name.

http://en.wikipedia.org/wiki/Alexander_Stepanov

In the above wiki, the C++ templates creator did mention Ada have those templates before it was in C++. If Ada compiler can do it, maybe C++ compiler writer want to 'talk' to Ada compiler writers how they overcome this technical difficulty ?

I have been waiting for quite a long time for this issue to be resolved :)
I believe that is because Ada doesn't not have the separation of declarations/definitions that C/C++ have.

If you wrote the code in Ada, you'd only have one file, which in this case would be the .h(pp) with the code inside it.
closed account (EzwRko23)
C++ won't have it because implementing this would require:
1. generic type bounds (like C#, Java and Scala have)
2. a VM or at least a smart, optimizing linker

The first one will require probably 5 or more years, the second one will probably never get its way into C++.

Just as jsmith said, the compiler has to generate many versions of the code, and because it haven't got a slightest idea what types can T mean until the template is concretized, it must have all the calling code at hand (in the header file).

The VM languages do that differently - they generate a few specialized versions of the code for the primitive types, and a one common version for the most generic user type (like Object in Java), so the code can be compiled separately, without knowing how it is used. Such code can be later specialized and optimized at runtime, by a smart VM. All this together can allow for eating the cake and having the cake: i.e. separate compilation of modules + no performance penalty.
Last edited on
Thanks everyone for your help on my Template issues. Worked like a charm, it's a shame I needed to specify a type with the extra definition. After reading up on it further and the comments it's nice to know why this is the behavior.
Topic archived. No new replies allowed.