編集:これは実際には解決策ではありません。それはもっとチートです。でも、必要なことはしてくれていると思います。
#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)
をかければ問題なく機能します (完全な転送が必要な場合を除きますが、それは些細なことです)。
そこで、上記のようなファンクターをオンザフライで構築するという次のアイデアがありました。これは基本的に、それにラムダ式を与えることを意味します。ラムダ自体は簡単なボイラープレートです。それからマクロを作成するのに十分簡単です:
// 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;
}
しかし、ラムダは、他の美徳とともに、キャプチャがない限り、自動的に関数ポインターに変換できることを思い出しました。そして、このラムダにはキャプチャがありません。唯一の外部シンボルは関数自体であり、それは自動ストレージ クラスを持つオブジェクトではないためです。つまり、要するに、実際には少し定型文でこれを行うことができるということです。
#define INVOKE(hof, func, arg) \
hof([](const decltype(arg)& arg_){return func(arg_);}, arg);