简体   繁体   中英

C++ templating, passing a function pointer with a parameterized return type

I want to parameterize the return value of a function to match the return value of a function pointer I pass it. I've only dealt with java generics before, so there's a good chance I'm completely missing something here.

the function looks like:

<in header>
template <typename T> static T getItems(const char* xpath, T (*getThings)(xpath_node_set*));

<in body>
template <typename T>
T XMLAdapter::getItems(const char* cpath, T(*getThings)(xpath_node_set*)){
    return getThings(head.select_nodes(path));
}

and the function i'm passing into it looks like this:

size_t handler(xpath_node_set* in){
    return in->size();
}

And the error i'm getting is:

Error   1   error LNK2019: unresolved external symbol \
"public: static unsigned int __cdecl XMLAdapter::getItems<unsigned int>(char const *,unsigned int (__cdecl*)(class pugi::xpath_node_set *))" (??$getItems@I@XMLAdapter@@SAIPBDP6AIPAVxpath_node_set@pugi@@@Z@Z) \
 referenced in function _wmain  C:\Users\Adam\SkyDrive\Documents\proj\ray\ray\ray.obj   ray

What gives?

remove the static from the prototype, it makes your function file local (ie invisible to other TUs).

Generally the function template definition should appear in the header, not a separate .cpp file.

Template functions need to be fully implemented (not just declared) in the header or you'll hit linker errors like this, if your caller and the template function are not in the same .cpp file.

Think about it this way: When you run the compiler on your code, you're actually compiling a separate .obj file for every single .cpp file. From the point of view of the compiler, these are completely independent black boxes. Every .cpp file could be compiled in parallel, and there are zero dependencies between them. The only dependcies are function declarations (specified in headers) which say "yeah, yeah...someone else is implementing this, let the linker complain if it can't find it."

When you have a template function, what you're really making is a recipe for how to make a function. If you have Foo<T> and you want to call it with int's and with string's, there are literally two generated functions that are completely symbolically different in your final binary: Foo<int> and Foo<string>.

That said, if you have your implementation of your template function in a separate .cpp file from someone who is trying to call a specialized version of it, they have no way to "cook" a new version of that function with whatever template arguments they are supplying. All they have is a header that says "Foo<T> is a function someone else implemented" to appease the linker. But your TemplateImplementation.cpp has no way of knowing that it should have generated a Foo<int> and a Foo<string>.

This is why you'll always see template libraries shipped as header-only libraries. No one could ship you a lib with compiled template functions if they wanted to, because they can't generate the functions until you have called specific versions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM