Original question
In response to the original question; this is a mistake, are there any workarounds?
Yes, it looks like you found a bug in VS2008, I tested it with VS2008 and VS2013.2 with the same linker error. I would advise you to file a bug report using Microsoft . Are there any workarounds, I think it might be.
As you noted, it seems that the compiler "loses" the implicit creation of the foo<int> template somewhere between decay to void (*Function)(T,void*) and when it is necessary during communication. Having played a little with the code, I think that it can include the apply(M) template and Microsoft parsing methods; because if apply simply accepts int as its argument to apply(int) (i.e. there is no template), it seems happy to compile and link it.
To get around this, you can modify the code as follows (by adding a default constructor and changing the apply call that must be made from the kernel instance). I know this may seem ugly; but it works around the problem and can help you solve the problem in your project.
#include <iostream> // Simple function template<class T> void foo(T a,void* = 0) { std::cout << a << std::endl; } // A distpatching class template<class T, void(*Function)(T,void*)> class kernel { void (*dummy)(T,void*); public: kernel() : dummy(Function) { // "Force" an implicit instantiation... // dummy can be either a member variable or declared in // in the constructor here. It exists only to "force" // the implicit instantiation. // Alternative... //void* dummy = (void*)Function; //(void)dummy; // silence "unused" warnings } // Function dispatcher template<class M> inline static void apply(M t) { Function(t,0); } }; int main() { kernel<int,foo>().apply(5); // The kernel temporary instantiation is only needed once for the // following line to link as well. //kernel<int,foo>::apply(5); }
The code compiles and communicates with VS2008, VS2013 and gcc.
How does code work with modern compilers?
Regarding comments published on the first issue; why and how does it work with a modern compiler? It is centered around two objects in C ++.
- Function pointer failure
- With any additional rules, if applicable (e.g. templates)
- Implement an implicit function template
When foo supplied, void(*Function)(T,void*) is decomposed and the pointer is used, as if &foo .
Convert functions to index 4.3
1 The value l of type of function T can be converted to prvalue of type "pointer to T". The result is a function pointer
A guide to conversions from operator to index 13.4 for additional rules in the presence of overloaded functions. Pay attention to the information about using & and when the function is a template (my selection).
Overloaded function address 13.4
1 The name of the function template is considered to be the named set of overloaded functions ... The overloaded function name can be preceded by the operator and.
2 If the name is a function template, the template argument is output (14.8.2.2), and if the argument output is completed, the resulting list of template arguments is used to create a specialized specialized function that is added to the set of overloaded functions.
Given the pointer and subtraction of the compiler of the required type T for the function foo , which is int in this case. The compiler then generates the code for the void foo(int,void*) function, and then uses it during the binding.
Implicit instance creation 14.7.1
3 If a specialization of a function template has not been explicitly instantiated or explicitly specialized, a specialization of a function template is implicitly created when the specialization is referenced in a context requiring a function definition.
Quotes taken from C ++ WD n3797