Templated function pointer as function argument

Sep 15, 2010 at 4:01am
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

Sep 15, 2010 at 6:00am
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.
Sep 15, 2010 at 6:03am
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!

Sep 15, 2010 at 10:46am
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?
Sep 15, 2010 at 12:12pm
@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.

Sep 16, 2010 at 8:36am
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) ){}
Sep 16, 2010 at 9:57am
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 Sep 16, 2010 at 9:58am
Sep 16, 2010 at 1:22pm
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.)

Sep 16, 2010 at 1:35pm

(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
Sep 16, 2010 at 3:18pm
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.

Sep 17, 2010 at 2:26am
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 :)
Sep 17, 2010 at 6:50am
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.
Sep 17, 2010 at 11:38am
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 Sep 17, 2010 at 11:42am
Sep 17, 2010 at 9:14pm
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.