使用可变参数模板在C++中包装函数指针

0xb*_*7ed 14 c++ templates function-pointers variadic-templates c++11

问题

我有一个号码的C++函数void f(),R g(T a),S h(U a, V b)等.我想写一个接受一个模板功能f,g,h等作为模板参数,并调用该函数.

我想要这样的东西:

template<MagicStuff, WrappedFunction>
ReturnType wrapper(MagicallyCorrectParams... params)
{
    extra_processing(); // Extra stuff that the wrapper adds
    return WrappedFunction(params);
}
...
wrapper<f>(); // calls f
wrapper<g>(T()); // calls g
wrapper<h>(U(), V()); // calls h
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止所尝试的:

解决方案1

template<typename ReturnType, typename Args...>
ReturnType wrapper(ReturnType (*wrappee)(Args...), Args... args)
{
    extra_processing();
    return wrappee(args...);
}
...
wrapper(f); // calls f OK
wrapper(g, T()); // calls g OK
wrapper(h, U(), V()); // calls h OK
Run Code Online (Sandbox Code Playgroud)

这有效但不能令人满意,因为在我的情况下,我希望函数指针绑定到模板实例.函数指针在编译时是静态可确定的,在我的用例中不希望在运行时将其作为参数传递.

解决方案2

template<
    typename ReturnType, typename Args...,
    ReturnType (*FuncPtr)(Args...)
>
wrapper(Args... args)
{
    extra_processing();
    return FuncPtr(args...);
}
...
wrapper<void, f>(); // calls f
wrapper<R, T, g>(T()); // calls g
wrapper<S, U, V, h>(U(), V()); // calls h
Run Code Online (Sandbox Code Playgroud)

这有效但不令人满意,因为它很冗长.返回类型和参数类型可以从函数指针本身推导出来.什么是完美的模板规范,所以我可以做wrapper<g>(T())如上所述.

谢谢大家的帮助!

Gin*_*lus 12

template<typename Fn, Fn fn, typename... Args>
typename std::result_of<Fn(Args...)>::type
wrapper(Args&&... args) {
    return fn(std::forward<Args>(args)...);
}
#define WRAPPER(FUNC) wrapper<decltype(&FUNC), &FUNC>
Run Code Online (Sandbox Code Playgroud)

//用法:

int min(int a, int b){
    return (a<b)?a:b;
}

#include<iostream>
#include<cstdlib>
int main(){
    std::cout<<WRAPPER(min)(10, 20)<<'\n';
    std::cout<<WRAPPER(rand)()<<'\n';
}
Run Code Online (Sandbox Code Playgroud)

或者,为了获得可能性相当低,但语法更短:

#define WRAPPER(FUNC, ...) wrapper<decltype(&FUNC), &FUNC>(__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)

//用法:

int main(){
    sdt::cout<<WRAPPER(min, 10, 20)<<'\n';
    std::cout<<WRAPPER(rand)<<'\n';
}
Run Code Online (Sandbox Code Playgroud)