gpt4 book ai didi

c++ - 在元组中迭代和调用异构函数

转载 作者:搜寻专家 更新时间:2023-10-31 01:53:09 26 4
gpt4 key购买 nike

用最一般的术语来说,我的问题如下:在编译时定义一系列异构函数指针(可能具有不同的元数),稍后需要在运行时以任意顺序迭代和调用。

将自己局限在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' 发送到标准输出

最佳答案

您应该将函数对象存储为 std::vector<std::function<const boost::mpi::communicator&, const T1*, int, T1*, int>> .它更易于管理。

如果您必须使用函数元组,请参阅下文。


C++ 标准库严重需要编译时间 iota .

如果您需要使用相同的参数调用所有函数,这里有一个替代方法。首先我们构建可变整数列表 integers<0, 1, 2, ..., n-1> (从 https://github.com/kennytm/utils/blob/master/vtmp.hpp 复制):

template <size_t... ns>
struct integers
{
template <size_t n>
using push_back = integers<ns..., n>;

};

namespace xx_impl
{
template <size_t n>
struct iota_impl
{
typedef typename iota_impl<n-1>::type::template push_back<n-1> type;
};

template <>
struct iota_impl<0>
{
typedef integers<> type;
};
}

template <size_t n>
using iota = typename xx_impl::iota_impl<n>::type;

然后我们直接使用解包操作:

template <typename... T, size_t... ns, typename... Y>
void call_all_impl(const std::tuple<T...>& funcs,
const integers<ns...>&,
Y... args) {
__attribute__((unused))
auto f = {(std::get<ns>(funcs)(args...), 0)...};
}

template <typename T, typename... Y>
void call_all(const T& funcs, Y&&... args) {
call_all_impl(funcs,
iota<std::tuple_size<T>::value>(),
std::forward<Y>(args)...);
}

例如,

int main() {
call_all(std::make_tuple([](int x, double y){ printf("1: %d %g\n", x, y); },
[](double x, int y){ printf("2: %e/%d\n", x, y); },
[](int x, int y){ printf("3: %#x %#x\n", x, y); }),
4, 9);
}

打印

1: 4 92: 4.000000e+00/93: 0x4 0x9

A slight modification can make it call just the i-th argument selected at runtime.

template <typename... T, size_t... ns, typename... Y>
void call_one_impl(const std::tuple<T...>& funcs, size_t which,
const integers<ns...>&,
Y... args) {
__attribute__((unused))
auto f = {(ns == which && (std::get<ns>(funcs)(args...), 0))...};
}

template <typename T, typename... Y>
void call_one(const T& funcs, size_t which, Y&&... args) {
call_one_impl(funcs, which,
iota<std::tuple_size<T>::value>(),
std::forward<Y>(args)...);
}

例如,

int main() {
auto t = std::make_tuple([](int x, double y){ printf("1: %d %g\n", x, y); },
[](double x, int y){ printf("2: %e/%d\n", x, y); },
[](int x, int y){ printf("3: %#x %#x\n", x, y); });

call_one(t, 2, 6.5, 7.5);
call_one(t, 0, 4, 9);
call_one(t, 1, 5.8, 8);
}

打印

3: 0x6 0x71: 4 92: 5.800000e+00/8

关于c++ - 在元组中迭代和调用异构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11505961/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com