Calling Function Template Specialization Using C Calling Conventions

Calling function template specialization using C calling conventions

What does the C header look like? Somewhere, the C source must enumerate the callback types allowed. You should take that opportunity to have a series of macros that generate prototypes to individual stub functions, with a corresponding sequence of macros in the C++ source generating extern "C" stubs.


As to the second question: Yes, that works, but the typedef is not inside a template. I attempted to put such a typedef inside a class, but it turns out that even class templates are not allowed inside the extern "C". So you can have a function template, but no parameters of dependent type.

Merely defining that function is easy:

extern "C" typedef void ftype(int);

template<typename T>
static ftype f; // <- added "static" here

template< typename T >
void f(int q) {}

Aha, variadic functions!

extern "C" typedef void ftype( int, ... );

template<typename T>
static ftype f;

template< typename T >
static void f( int z, ... ) {
va_list va;
va_start( va, z );
T v = va_arg( va, T );
va_end( va );

std::cout << v;
}

You don't really need type deduction since it's just a callback, so you can pass this & f<int> to the C code, all callbacks having the same type, and it can make the type determination at runtime and pass whatever it wants through the varargs.

Is it allowed to pass a pointer to a template function to C library? (as a callback)

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).

Calling a template function from a C file

Since you mix C and C++ already (and therefore must have taken care of the possible issues), another solution is to continue developing the application in C++. That way new code can use all the nice features of the C++ library, like templates ;-), overloaded functions etc., and has access to C++'s standard library which can greatly enhance productivity.

I don't see principal obstacles to using C++ for new source files in the application; whether it's easily possible and worthwhile to switch existing C files to C++ upon edits is another question.

Template partial specialization for __stdcall function pointer

No, this is by design. The calling convention is very much part of the function declaration, your template function uses the default calling convention. Which is not __stdcall unless you compile with /Gz. The default is /Gd, __cdecl.

The code compiles when you target x64 because it blissfully has only one calling convention.

Fix:

template<class R, class T0, class T1>
class TFunction<R (__stdcall *)(T0,T1)>
{
// etc..
};

Call C++ nonmember function from C

No. It's not guaranteed that it uses the same calling convention. You can use the calling convention modifiers like _stdcall, cdecl, pascal, etc. So you have to make sure that both sides know the same calling convention.

One way would be detecting the mangled name and define a proper prototype for the C function.

Consider changing the design; since you can't benefit from the template in C anyway, you can define a simple C++ function (defined extern "C") that calls the templated function.

Function template specialization importance and necessity

Basically the idea is that you can write templates that behave in a generic way for the general case, but can still handle special cases. One example of where specialization is used is in std::vector. std::vector<bool> is a specialization that packs the bool elements such that they only use one bit per element, not one byte. std::vector<T> works like a normal dynamic array for all other types.

The more advanced use for specialization is metaprogramming. For example, here's an example (from Wikipedia) of how to use template specialization to compute factorials at compile time.

template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0>
{
enum { value = 1 };
};


Related Topics



Leave a reply



Submit