gpt4 book ai didi

c++ - 将返回 std::future 的函数改编为 std::future

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:24:02 27 4
gpt4 key购买 nike

假设我有一个异步功能映射原语,它接受 std::vector作为输入并返回 std::futureContainer我选择的输出:

template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return std::async([=]
{
Container result(in.size());

for(size_t i = 0; i < in.size(); ++i)
{
result[i] = f(in[i]);
}

return result;
});
}

我想构建一个类似的 async_for_each通过调整功能 async_map :

template<class T, class Function>
std::future<void> async_for_each(const std::vector<T>& in, Function f);

问题是 async_for_each返回 std::future<void> , 而 async_map返回 std::future<Container> , 和 void不是 Container .

通过构造满足 Container 的类型,我可以获得接近我想要的东西要求,但忽略了对它的分配(在我最初的尝试中为 empty_container),但是 std::future这种类型仍然不是std::future<void> .

我的解决方案有以下限制:

  • async_map 必须只有一个实现,具有给定的函数签名(即没有 async_map<void> 特化)
  • 必须只有一个 std::future已创建(即没有 .then() 样式的延续)

我希望有一种有效的方法可以在 std::future 之间进行转换s 相关类型(或将 std::future<T> 转换为 std::future<void> ),但对 this question 的回答表明这是不可能的。

随机想法:

  • 可以async_for_each以巧妙的方式包装其功能来解决这个问题?
  • 可以使用 Container 的类型吗?表现得像voidasync_for_each , 但表现得像 Containerasync_map

我的初步尝试如下。考虑到这些限制,是否可以构建我想要的东西?

#include <future>
#include <vector>
#include <iostream>

template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return std::async([=]
{
Container result(in.size());

for(size_t i = 0; i < in.size(); ++i)
{
result[i] = f(in[i]);
}

return result;
});
}

struct empty_container
{
empty_container(size_t) {}

struct empty
{
template<class T>
empty operator=(const T&) const { return empty(); }
};

empty operator[](size_t) { return empty(); }
};

template<class Function>
struct invoke_and_ignore_result
{
Function f;

template<class T>
empty_container::empty operator()(T&& x) const
{
f(std::forward<T>(x));
return empty_container::empty();
}
};

template<class T, class Function>
//std::future<void> async_for_each(const std::vector<T>& in, Function f)
std::future<empty_container> async_for_each(const std::vector<T>& in, Function f)
{
invoke_and_ignore_result<Function> g{f};

std::future<empty_container> f1 = async_map<empty_container>(in, g);

return f1;
}

int main()
{
std::vector<int> vec(5, 13);

async_for_each(vec, [](int x)
{
std::cout << x << " ";
}).wait();

std::cout << std::endl;

return 0;
}

最佳答案

我认为您使用了错误的原语。

在这里,我用一个不同的原语——一个水槽来构建一切。

接收器可以通过operator()(T&&)& 消费数据。然后它通过 operator()()&& 返回一些结果。

这是一个 async_sink 函数:

template<class Container, class Sink>
std::future<std::result_of_t<std::decay_t<Sink>()>>
async_sink(Container&& c, Sink&& sink)
{
return std::async(
[c=std::forward<Container>(c), sink=std::forward<Sink>(sink)]
{
for( auto&& x : std::move(c) ) {
sink( x );
}

return std::move(sink)();
});
}

这是一个 sink 的实现,它将东西放入容器中,然后返回它:

template<class C>
struct container_sink_t {
C c;
template<class T>
void operator()( T&& t ){
c.emplace_back( std::forward<T>(t) );
}
C operator()()&&{
return std::move(c);
}
};

这是一个接受函数和一个接收器并将它们组合在一起的接收器:

template<class F, class S>
struct compose_sink_t {
F f;
S s;
template<class T>
void operator()(T&& t){
s(
f(std::forward<T>(t))
);
}
std::result_of_t<S()> operator()()&&{
return std::move(s)();
}
};

template<class C, class F>
compose_sink_t<std::decay_t<F>, container_sink_t<C>>
transform_then_container_sink( F&& f ) {
return {std::forward<F>(f)};
}

这是一个接受函数、调用它并返回 void 的接收器:

template<class F>
struct void_sink_t {
F f;
template<class T>
void operator()(T&& t)
{
f(std::forward<T>(t));
}
void operator()() {}
};
template<class F>
void_sink_t<std::decay_t<F>> void_sink(F&&f){return {std::forward<F>(f)}; }

现在你的 map 是:

template<class Container, class T, class Function>
std::future<Container> async_map(const std::vector<T>& in, Function f)
{
return async_sink(
in,
transform_then_container_sink<Container>(std::forward<F>(f))
);
}

你的 for_each 是:

template<class T, class Function>
std::future<void> async_for_each(const std::vector<T>& in, Function f)
{
return async_sink(
in,
void_sink(std::forward<F>(f))
);
}

我自由地使用 C++14 特性,因为它们使代码变得更好。您可以用一个拷贝替换 move-into-container 以降低效率,并编写您自己的 _t 别名。

以上代码没有经过测试和运行,所以可能存在bug。有一个问题我不确定——返回 void 的 lambda 是否可以在该上下文中以 return void_func() 结束? -- 但由于这种丑陋之处在于一个地方,因此即使它不起作用也可以解决。

关于c++ - 将返回 std::future<T> 的函数改编为 std::future<U>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30223186/

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