Reputation: 101
I have this template function, which is working well:
template<typename RES, typename... PARMS> SQInteger GlobalBind(RES(*fn)(PARMS... parms), const char *sqName, HSQUIRRELVM v)
Which is called like this :
GlobalBind(aFunction, "aName", vm);
Its scope is binding function fn
to a scripting engine.
Using it in this way, I must keep the fn
pointer AND a proxy template pointer inside of the scripting engine; the proxy template (not shown here) is called with fn
as parameter, does some stuff, and then calls fn
.
What I'd like to achieve is to remove the fn
pointer from the function call, and put it into the template as a parameter, something like this:
template<typename RES, typename... PARMS, RES(*fn)(PARMS...)> SQInteger GlobalBind(const char *sqName, HSQUIRRELVM v)
So, a specific template is instantiated for each different fn
, which means that I could avoid the fn
pointer in the scripting language; the call should be:
GlobalBind<aFunction>("aName", vm);
The template declaration is accepted by the compiler, but the call brings errors, even adding the parameter types before aFunction
, like this (assuming aFunction
returns and int
and has const char *
as a parameter):
GlobalBind<int, const char *, aFunction>("aName", vm);
Is there a way to achieve this result (the former, without a parameters list)?
EDIT: to simplify the question, is the template
template<typename RES, typename... PARMS, RES(*fn)(PARMS...)> RES TEST(PARMS... parms) {
return fn(parms...);
}
a valid one ? And if yes... how should it be called ? I tried this :
int testfn(const char *s) { return strlen(s); }
TEST<testfn>("aString"); << ERROR
TEST<int, const char *, testfn>("aString"); << ERROR
EDIT2: This one :
template<int (*fn)(const char *)> int TEST2(const char *s) {
return fn(s);
}
TEST2<testfn>("aString");
works, but it's not useful for my purpose
Upvotes: 0
Views: 781
Reputation: 101
Found an (ugly) solution, but it works also for overloaded functions :
int myFunc(const char *s) {
return strlen(s);
}
const char *myFunc(int i) {
return "it's me";
}
template<typename FN, FN fn, typename RES, typename... PARMS> RES _DISPATCH(PARMS... parms) {
return fn(parms...);
}
#define DISPATCH(RES, FN, ...) _DISPATCH<RES(*)(__VA_ARGS__), FN, RES, __VA_ARGS__>
Cout() << (void *)DISPATCH(int, myFunc, const char *) << "\n";
Cout() << (void *)DISPATCH(const char *, myFunc, int) << "\n";
The DISPATCH() macro builds a dispatcher of which I can get the C address and pass to my scripting engine. I'd rather to have a solution without macros, indeed. Still open to better solutions!
Upvotes: 0
Reputation: 275330
template<class T, T t>
struct constant_t:std::integral_constant<T,t>{
constexpr operator T()const { return t; }
constexpr constant_t(){}
};
#define TYPEDARG(...) \
typename std::decay<decltype(__VA_ARGS__)>::type, \
__VA_ARGS__
Now constant_t<TYPEDARG(foo)>
is a type whose instances can be invoked if foo
is a non-overloaded function and they call foo
.
In c++17 this becomes:
template<auto x>
using constant_t=std::integral_constant<std::decay_t<decltype(x)>,x>;
and use is simply constant_t<foo>
, without all that extra noise.
template<class Fn, class R, class... Args>
R test(Args&&... args) {
return Fn{}(std::forward<Args>(args)...);
}
int foo( int a, int b ) { return a+b; }
int r = test< constant_t<TYPEDARG(foo)>, int, int, int >( 3, 4 );
Upvotes: 3