编辑:这不是真正的解决方案;这更像是一个骗局。但我认为它可以满足需要。
#define INVOKE(hof, func, arg) \
hof([](const decltype(arg)& arg_){return func(arg_);}, arg)
例子:
// This function mimics the signature of QtCollector::run for testing
template <typename Functor, typename Arg1>
auto QtConcurrent_run(Functor functor, const Arg1 &arg1)
-> decltype(functor(arg1))
{
return functor(arg1);
}
#include <iostream>
int f(int x) { std::cout << "int" << " " << x << std::endl; return x; }
double f(double x) { std::cout << "double" << " " << x << std::endl; return x; }
int main() {
INVOKE(QtConcurrent_run, f, 3);
INVOKE(QtConcurrent_run, f, 3.14);
INVOKE(QtConcurrent_run, f, '3');
return 0;
}
在ideone上看到它。
出于历史目的和一些解释,原始答案如下。
只是为了清楚起见,因为这是一个有趣的问题,但也许让您的项目移动对您来说更重要,您是否有理由不想将各种函数覆盖包装到函子结构中,并传递函子struct 直接到 QtConcurrent::run ,哪个会欣然接受这样的事情?
如果函数的所有定义都在一个类中,那么就没有问题:
struct f_collector {
ReturnType1 f(ArgType1 arg);
ReturnType2 f(ArgType2 arg);
ReturnType3 f(ArgType3 arg);
// ...
// Make it a functor:
template<typename Argtype>
auto operator()(const Argtype& arg) -> decltype(f(arg)) { return f(arg); }
}
然后你可以打电话QtConcurrent::run(f_collector(), argument)
,它会正常工作(除非你需要完美的转发,但这是一个小细节)。
所以我有了以下想法,即动态构建一个像上面这样的函子,这基本上意味着给它一个 lambda 表达式。lambda 本身就是很简单的样板;很容易从中制作宏:
// This is the functor
template<typename Arg, typename Func> struct wrapper {
wrapper(Func f) : f(f) {}
const Func f;
auto operator()(Arg arg) const -> decltype(f(arg)) {return f(arg);}
};
// As usual, a make_* function, because you can't template deduce a constructor
template<typename Arg, typename Func>
wrapper<Arg, Func> make_wrapper(Func f) {
return wrapper<Arg, Func>(f);
}
// Boilerplate inside a macro
#define INVOKE(hof,func,arg) \
hof(make_wrapper<decltype(arg)>( [](const decltype(arg)& arg_) { \
return func(arg_); \
}), \
arg)
// The above was ugly, but it's easy to use. For testing, I define
// this with a similar signature to QtConcurrent::run
template <typename Functor, typename Arg1>
auto QtConcurrent_run(Functor functor, const Arg1 &arg1)
-> decltype(functor(arg1))
{
return functor(arg1);
}
#include <iostream>
int f(int x) { std::cout << "int" << " " << x << std::endl; return x; }
double f(double x) { std::cout << "double" << " " << x << std::endl; return x; }
int main() {
INVOKE(QtConcurrent_run, f, 3);
INVOKE(QtConcurrent_run, f, 3.14);
INVOKE(QtConcurrent_run, f, '3');
return 0;
}
但是后来我想起了 lambda 以及它们的其他优点,只要它们没有捕获,就可以自动转换为函数指针。而且这个 lambda 没有捕获,因为唯一的外部符号是函数本身,而不是具有自动存储类的对象。所以,我认为底线是,你实际上可以用一些样板来做到这一点:
#define INVOKE(hof, func, arg) \
hof([](const decltype(arg)& arg_){return func(arg_);}, arg);