I'm basically looking to generate a wrapper for a generic C function without having to manually specify the types. So I have a callback with a fixed prototype but I'm going to need to do some special code in the wrapper based on the type of the wrapped function... So basically I'm thinking about using a static method in a class template to wrap my function to a conforming interface e.g.:
// this is what we want the wrapped function to look like
typedef void (*callback)(int);
void foobar( float x ); // wrappee
// doesn't compile
template< T (*f)(S) > // non-type template param, it's a function ptr
struct Wrapper
{
static void wrapped(int x)
{
// do a bunch of other stuff here
f(static_cast<S>(x)); // call wrapped function, ignore result
}
}
And then I'd like to do something like:
AddCallback( Wrapper<foobar>::wrapped );
However, the problem is that I can't just go ahead and use a "S" in the parameter of the function in the Wrapper template, I have to first list it as a parameter:
template< class T, class S, T (*f)(S) >
struct Wrapper
// ...
But this means it's a lot more painful to use (Wrapper<void,float,foobar>::wrapped
), ideally I'd like to just pass in the function pointer there and have it work out the types of the parameters (and return types) automatically. To be clear, inside the wrapped function I'm going to need to refer to the types of the function pointer (so I do need some equivalent of S or T).
Is there a way of doing this?
Non-type template arguments are normally used to initialize a class or to specify the sizes of class members. For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.
A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
What can be passed by non-type template parameters during compile time? Explanation: Non-type template parameters provide the ability to pass a constant expression at compile time. The constant expression may also be an address of a function, object or static class member.
One thing you might wish to consider is using LLVM or similar to generate an appropriate trampoline function at runtime. Or here's a static solution:
#include <iostream>
void f(float f) { std::cout << f << std::endl; }
template<typename T, typename S> struct static_function_adapter {
template<T(*f)(S)> struct adapt_container {
static void callback(int v) {
f(static_cast<S>(v));
}
};
template<T(*f)(S)> adapt_container<f> adapt() const {
return adapt_container<f>();
}
};
template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) {
return static_function_adapter<T, S>();
}
#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback)
int main() {
void (*adapted)(int) = ADAPTED_FUNCTION(f);
adapted(42);
return 0;
}
The get_adapter function allows us to infer the argument and return type; adapt() then converts this into a type parameterized on the actual function, and finally we get a static function in callback.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With