所以有几种方法。
您可以按照建议等待 await 关键字到达,但这似乎是长期的。如果您确实等待 await,这里有人用 await 实现了 yield,至少乍一看应该可以在 C++ 中使用。
您可以编写一个生成迭代器助手,或者从 boost 中借用一个,并从中制作一个生成器。
您可以使用存储在 a 中的可变 lambda std::function
,可能返回 a std::experimental::optional
(或 boost 可选)。
但那些大多只是让它变得漂亮。所以让我们变得丑陋。我会用 C++14 写这个,因为懒惰。
struct generator {
using trees=std::vector<tree>;
trees m_cur;
trees m_next;
bool next(value* v){
while(true){
if (m_cur.empty()){
m_cur=std::move(m_next);
m_next.clear();
std::reverse(begin(m_cur),end(m_cur));
if(m_cur.empty())
return false;
}
auto t = m_cur.back();
m_cur.pop_back();
if(!t)continue;
*v = get_value(t);
m_next.push_back(get_left(t));
m_next.push_back(get_right(t));
return true;
}
}
generator(tree t):m_cur{t}{};
};
树类型需要自由函数来获取值、获取左右和运算符!判断它是否为空。它需要是可复制的(指针可以)。
利用:
generator g(some_tree);
value v;
while(g.next(&v)){
std::cout<<v<<'\n';
}
现在这很难看——例如,我们手动维护状态。
我相信通过 await 会出现一种更神奇的方式,但这不是标准化的。
生成器迭代器会将丑陋的接口隐藏在迭代器门面后面,但状态仍然是手动管理的。
你也许可以用 lambda 做一些花哨的事情,但我不确定 lambda 是否可以返回它自己的类型。也许。(G:{}->{G,Maybe X} 或类似的)
现在,因为它太棒了,这里是n4134提出的await
/yield
解决方案。
template<class T0, class...Ts>
std::vector<std::decay_t<T0>> vec_of(T0&& t0, Ts&&... ts) {
return {std::forward<T0>(t0), std::forward<Ts>(ts)...};
}
auto breadth_first = [](auto&& tree){
auto tree_list = vec_of(decltype(tree)(tree));
while(!tree_list.empty()) {
decltype(tree_list) new_tree_list;
for(auto&& tree:tree_list) {
if (tree) {
yield get_value(tree);
new_tree_list.push_back(get_left(tree));
new_tree_list.push_back(get_right(tree));
}
}
tree_list = std::move(new_tree_list);
}
};
这基本上是python代码的逐行翻译。我确实写了一个vec_of
辅助函数来替换[]
python。
利用:
for(auto&& value : breadth_first(tree)) {
std::cout << value;
}
这很漂亮。