C++ &引用;“收益率”;C++;,如何从函数返回迭代器?

C++ &引用;“收益率”;C++;,如何从函数返回迭代器?,c++,iterator,generator,coroutine,yield-keyword,C++,Iterator,Generator,Coroutine,Yield Keyword,考虑以下代码 std::vector<result_data> do_processing() { pqxx::result input_data = get_data_from_database(); return process_data(input_data); } std::vector<result_data> process_data(pqxx::result const & input_data) { std::vecto

考虑以下代码

std::vector<result_data> do_processing() 
{
    pqxx::result input_data = get_data_from_database();
    return process_data(input_data);
}

std::vector<result_data> process_data(pqxx::result const & input_data)
{
    std::vector<result_data> ret;
    pqxx::result::const_iterator row;
    for (row = input_data.begin(); row != inpupt_data.end(); ++row) 
    {
        // somehow populate output vector
    }
    return ret;
}

如果我正确地解释了杰瑞·科芬斯的笔记,这就是他建议的,不是吗?如果是这样,我怎么能在C++中实现这个?

< p>有一个Boost的博客文章。Asio作者Chris Kohlhoff对此进行了说明:

他用宏模拟
产量

#define yield \
  if ((_coro_value = __LINE__) == 0) \
  { \
    case __LINE__: ; \
    (void)&you_forgot_to_add_the_entry_label; \
  } \
  else \
    for (bool _coro_bool = false;; \
         _coro_bool = !_coro_bool) \
      if (_coro_bool) \
        goto bail_out_of_coroutine; \
      else

这必须与
coroutine
类结合使用。更多详情请参见博客。

不,杰瑞不是这个意思,至少不是直接的意思

Python实现中的yield。C++没有它们(但是它们当然可以被仿真,但是如果做得干净,那就有点牵连)。 但Jerry的意思很简单,您应该传入一个输出迭代器,然后将其写入:

template <typename O>
void process_data(pqxx::result const & input_data, O iter) {
    for (row = input_data.begin(); row != inpupt_data.end(); ++row)
        *iter++ = some_value;
}
模板
无效过程数据(pqxx::结果常数和输入数据,iter){
for(row=input_data.begin();row!=inpupt_data.end();++row)
*iter++=某个_值;
}
并称之为:

std::vector<result_data> result;
process_data(input, std::back_inserter(result));
std::向量结果;
处理数据(输入,标准::返回插入器(结果));

我不相信这通常比返回向量好。

我发现类似istream的行为会接近我的想法。考虑下面的(未经测试)代码:

struct数据源{
公众:
//用于传递数据项
数据源和操作员>>(输入数据t&i){
i=输入_data.front();
输入_data.pop_front();
归还*这个;
}
//用于布尔运算
运算符void*(){return input_data.empty()?0:this;}
私人:
std::deque输入数据;
//将新数据附加到专用输入_数据
//潜在异步
void从_数据库()获取_数据_;
};
现在,我可以按照以下示例执行操作:

int main () {
    data_source d;
    input_data_t i;
    while (d >> i) {
        // somehow process items
        result_data_t r(i);
        cout << r << endl;
    }
}
int main(){
数据源d;
输入数据;
而(d>>i){
//以某种方式处理项目
结果数据(i);

cout当您递归地解析某个内容或处理具有状态时,生成器模式可能是一个好主意,它可以极大地简化代码,但此时不容易进行迭代,通常回调是替代方法。我想让
产生
,并发现现在似乎可以使用它

下面的代码是
cat
文件的一个示例。当然,在您希望进一步处理文本行之前,它毫无意义:

#include <fstream>
#include <functional>
#include <iostream>
#include <string>
#include <boost/coroutine2/all.hpp>

using namespace std;

typedef boost::coroutines2::coroutine<const string&> coro_t;

void cat(coro_t::push_type& yield, int argc, char* argv[])
{
    for (int i = 1; i < argc; ++i) {
        ifstream ifs(argv[i]);
        for (;;) {
            string line;
            if (getline(ifs, line)) {
                yield(line);
            } else {
                break;
            }
        }
    }
}

int main(int argc, char* argv[])
{
    using namespace std::placeholders;
    coro_t::pull_type seq(
            boost::coroutines2::fixedsize_stack(),
            bind(cat, _1, argc, argv));
    for (auto& line : seq) {
        cout << line << endl;
    }
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
typedef boost::coroutines2::coroutine coro\t;
void cat(coro_t::push_type&yield,int argc,char*argv[])
{
对于(int i=1;iCUT只返回向量,它完全是完美的。(n)RVO将很可能处理这个问题,而C++(C++)11移动语义将在(n)RVO没有时执行。此外,<代码>返回进程数据(GETZATA DATAOFAXDABASEASE());几乎任何接受或返回容器而不是在迭代器上操作的代码都应该被认为是可疑的。"我会反驳这一点。这当然是一个很好的一般性建议,但让代码独立于容器类型的愿望常常被误导,它们除了语法之外不是很可交换的……传递“out”迭代器的一个大优势是,当调用两次
process\u data
时,代码会变得更有效——可能是在di上For输入数据-但是希望输出在同一个<代码>结果< /Cord>对象。效率是为什么你首先使用C++,对吗?那就允许调用方使用容器的自定义分配器。@弗雷里奇,我承认这是一个应该考虑的有效点。也许杰瑞的建议更一般。返回迭代器的另一个优点是,您不会强制调用方使用您决定的数据结构。
result
可以是一个集合。看起来很有趣!不幸的是,我仍然使用boost版本1.58()。但我稍后会尝试。感谢您的分享!@moooeeep您可以先尝试boost::coroutine。它应该与更多编译器兼容,但您不能在内容上使用基于C++11范围的for循环。您必须编写如下内容:while(seq){cout
#include <fstream>
#include <functional>
#include <iostream>
#include <string>
#include <boost/coroutine2/all.hpp>

using namespace std;

typedef boost::coroutines2::coroutine<const string&> coro_t;

void cat(coro_t::push_type& yield, int argc, char* argv[])
{
    for (int i = 1; i < argc; ++i) {
        ifstream ifs(argv[i]);
        for (;;) {
            string line;
            if (getline(ifs, line)) {
                yield(line);
            } else {
                break;
            }
        }
    }
}

int main(int argc, char* argv[])
{
    using namespace std::placeholders;
    coro_t::pull_type seq(
            boost::coroutines2::fixedsize_stack(),
            bind(cat, _1, argc, argv));
    for (auto& line : seq) {
        cout << line << endl;
    }
}