Is it allowed to pass a pointer to a template function to C library? (as a callback) [duplicate]
Asked Answered
B

1

12

Consider the following code:

#include <iostream>

struct Foo {
  void work() { std::cout << "foo" << std::endl; }  
};

typedef void function_type(void *arg);

template <typename T>
void function(void *arg)
{
    auto &t = *reinterpret_cast<T*>(arg);
    t.work();
}

void call_function(function_type *fn, void *arg)
{
    fn(arg);
}

int main()
{
    Foo foo;

    call_function(&function<Foo>, &foo);

    return 0;
}

If call_function() would be an interface of some C library (which is linked dynamically to my program), is it OK to pass a pointer to some specific instance of a template function? Are there any differences between pointers to (a instantiation of) a template function and regular functions?

Blaine answered 29/4, 2020 at 12:8 Comment(2)
I'd be surprised if not. An instantiation of a template function should not be different from an ordinary function.Duvetyn
That should work at the end, instances of template functions are just functions...Intercrop
H
12

In the code as shown, both the functions have C++ language linkage, and everything is fine. You're not passing a template function, you're passing a regular function instantiated from a function template.

Once any template is instantiated, it's not really a template any more, much like instantiating a class gives you an object, and not another class.

There is something missing though - for linking a C program, you need to import the interface as extern "C" and use that linkage for any function pointers you pass to it. Otherwise the C and C++ sides may disagree on the calling convention to use, and everything will go horribly wrong.

Since the standard explicitly says

A template, a template explicit specialization, and a class template partial specialization shall not have C linkage

we need some workaround. As usual, your C callback takes an argument, so there's nothing stopping you from switching calling conventions in a C-linkage trampoline function:

extern "C" {
    void bounce(void *arg)
    {
        static_cast<Trampoline *>(arg)->callback();
    }
}

where callback will be a normal C++-linkage function, including a function template instantiation (or just a std::function or whatever).

Herstein answered 29/4, 2020 at 12:22 Comment(4)
In other words... "no".Succursal
You are not passing a function, instantiated from a template or not. You are passing a function pointer.Tanguy
is it ok to have non-c cast inside extern"C"?Encase
@NooneAtAll Yes. Just because it's inside extern "C" doesn't mean it's C code, it just means that the code has C linkage.Consecution

© 2022 - 2024 — McMap. All rights reserved.