LNK2019 (VS 2008) with full implementation of template functions using template function pointers

The following minimal code compiles and links perfectly in GNU C ++:

#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 { public: // Function dispatcher template<class M> inline static void apply(M t) { Function(t,0); } }; int main() { kernel<int,foo>::apply(5); //foo(5,0); } 

but with Visual Studio 2008 it throws an error

 error LNK2019: Verweis auf nicht aufgelΓΆstes externes Symbol ""void __cdecl foo<int>(int,void *)" (??$foo@H@@YAXHPAX@Z)" in Funktion ""public: static void __cdecl kernel<int,&void __cdecl foo<int>(int,void *)>::apply<int>(int)" (??$apply@H@?$kernel@H$1??$foo@H@@YAXHPAX@Z@@SAXH@Z)". 

Obviously, the entire implementation of the function exists, but it seems that the compiler discards the implementation of the function foo . If the comment line is activated, the linker finds the character.

I think (since g ++ compiles it in order), is this valid code, so I assume there is some kind of error in VS 2008, or am I doing something wrong here? Does anyone know a workaround / solution for this? The final code should work with Visual Studio 2008 and in real code it is impossible to guess all combinations of template types (i.e. I cannot explicitly instantiate functions for all available types: here it is just T, in real code, 5 template parameters are used with arbitrary classes).

+8
c ++ visual-studio-2008 templates function-pointers lnk2019
source share
1 answer

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

+4
source share

All Articles