最も一般的な用語では、私の問題は次のとおりです。コンパイル時に、実行時に任意の順序で反復および呼び出す必要がある異種関数ポインターのシーケンス(潜在的に異なるアリティを持つ)を定義します。
自分自身をC++に制約しますが、最も適切なコンテナー、反復、および呼び出しメカニズムは何でしょうか?
この問題は、タプルを含まないより単純な解決策を後で見つけた現実世界の状況によって動機付けられましたが、それはより自然に特化しています。
もともと私はこのようなことをしようとしました:
//type variables Y... have to be convertible to parameters of every function from the tuple std::tuple<T...> in order for this to compile
template<size_t n, typename... T, typename... Y>
void callFunNth(std::tuple<T...> &tpl, size_t i, Y... args) {
if (i == n)
std::get<n>(tpl)(args...);
else
callFunNth<(n < sizeof...(T)-1? n+1 : 0)>(tpl, i, args...);
}
template<typename... T, typename... Y>
void callFun(std::tuple<T...> &tpl, size_t i, Y... args) {
callFunNth<0>(tpl,i, args...);
}
int main()
{
using T1 = int;
namespace mpi = boost::mpi;
//Several instantiations of boost::mpi::reduce algorithm I am interested in
auto algs = make_tuple(boost::bind((void (*)(const mpi::communicator&, const T1*, T1, T1*, std::plus<T1>, int))mpi::reduce<T1, std::plus<T1>>, _1, _2, _3, _4, std::plus<T1>(), _5),
boost::bind((void (*)(const mpi::communicator&, const T1*, T1, T1*, mpi::minimum<T1>, int))mpi::reduce<T1, mpi::minimum<T1>>, _1, _2, _3, _4, mpi::minimum<T1>(), _5),
boost::bind((void (*)(const mpi::communicator&, const T1*, T1, T1*, std::minus<T1>, int))mpi::reduce<T1, std::minus<T1>>, _1, _2, _3, _4, std::minus<T1>(), _5)
);
//Iterate through the tuple and call each algorithm
for(size_t i=0; i < std::tuple_size<decltype(algs)>::value;i++)
callFun(algs, i, /*actual arguments to each algorithm*/);
}
このアプローチの問題は、callFunNthがすべての提供された引数をコンパイルするには、提供されたタプル内のすべての関数のパラメーターに型変換可能である必要があることです。これにより、前述の関数の異質性が大幅に制限され、std::bindの使用が強制されます。またはboost::bindでこれを回避します。
タイプが相互に変換可能である場合、次のように書くことができます。
template <typename T, typename U>
void fja(T x, U y) {
std::cout << x << std::endl;
}
auto funs = std::make_tuple(fja<int,std::string>, fja<double,std::string>, fja<char,std::string>);
callFun(funs, 2, 'a', "Char");
callFun(funs, 1, 2.45, "Decimal");
callFun(funs, 0, 1, "Integer");
'a'、 '2.45'、および'1'をそれぞれstdoutに送信します