在最一般的术语中,我的问题如下:在编译时定义一系列异构函数指针(可能具有不同的arity),稍后需要在运行时以任意顺序迭代和调用。
把自己限制在 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”分别发送到标准输出