类似于C ++ LINQ的迭代器操作 [英] C++ LINQ-like iterator operations

查看:74
本文介绍了类似于C ++ LINQ的迭代器操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于受到Linq的污染,我不愿放弃.但是,对于某些事情,我只需要使用C ++.

Having been tainted by Linq, I'm reluctant to give it up. However, for some things I just need to use C++.

作为linq消费者(即对我而言),linq的真正优势不在于表达式树(操作起来很复杂),而在于我可以轻松混合和匹配各种功能.对于C ++样式的迭代器,是否存在.Where.Select.SelectMany.Skip.Take.Concat的等效项?

The real strength of linq as a linq-consumer (i.e. to me) lies not in expression trees (which are complex to manipulate), but the ease with which I can mix and match various functions. Do the equivalents of .Where, .Select and .SelectMany, .Skip and .Take and .Concat exist for C++-style iterators?

这些对于我编写的各种通用代码非常方便.

These would be extremely handy for all sorts of common code I write.

我不在乎LINQ特定的问题,这里的关键问题是能够在更高层次上表达算法,而不是让C ++代码看起来像C#3.0.我希望能够表达结果是由每个序列的前n个元素串联而成的",然后在需要新序列的地方重用这样的表达式,而无需手动(贪婪地)实例化中间体.

I don't care about LINQ-specifics, the key issue here is to be able to express algorithms at a higher level, not for C++ code to look like C# 3.0. I'd like to be able to express "the result is formed by the concatenation first n elements of each sequence" and then reuse such an expression wherever a new sequence is required - without needed to manually (and greedily) instantiate intermediates.

推荐答案

我对LINQ没有具体的经验,但是

I don't have concrete experience with LINQ, but the Boost.Iterator library seems to approach what you're referring to.

这个想法是要有一个函数(在LINQ中,IIUC,它们采用扩展方法的形式,但这不是基本的),并带有一个迭代器和一个函数,将它们组合起来以创建一个新的迭代器.

The idea is to have functions (IIUC, in LINQ, they take the form of extension methods, but that's not fundamental), taking an iterator and a function, combining them to create a new iterator.

LINQ哪里"映射到make_filter_iterator:

LINQ "Where" maps to make_filter_iterator:

std::vector<int> vec = ...;
// An iterator skipping values less than "2":
boost::make_filter_iterator(_1 > 2, vec.begin())

LINQ选择"映射到make_transform_iterator:

LINQ "Select" maps to make_transform_iterator:

using namespace boost::lambda;
//An iterator over strings of length corresponding to the value
//of each element in "vec"
//For example, 2 yields "**", 3 "***" and so on.
boost::make_transform_iterator(construct<std::string>('*', _1), vec.begin())

它们可以组成:

//An iterator over strings of length corresponding to the value of each element
// in "vec", excluding those less than 2
std::vector<int> vec = ...;
boost::make_transform_iterator(construct<std::string>('*', _1), 
    boost::make_filter_iterator(_1 > 2, vec.begin())
)

但是,这有一些令人讨厌的事情:

However, there are a few annoying things with this:

  • make_xxx_iterator(some_functor, some_other_iterator)返回的类型为xxx_iterator<type_of_some_functor, type_of_some_iterator>
  • 使用boost :: bind,lambda或phoenix创建的函子的类型很快变得难以管理且繁琐.
  • The type returned by make_xxx_iterator(some_functor, some_other_iterator) is xxx_iterator<type_of_some_functor, type_of_some_iterator>
  • The type of a functor created using boost::bind, lambda, or phoenix quickly becomes unmanageably large and cumbersome to write.

这就是为什么我在上面的代码中避免将make_xxx_iterator的结果分配给变量的原因. C ++ 0x的自动"功能将非常受欢迎.

That's why I avoided in the code above to assign the result of make_xxx_iterator to a variable. C++0x "auto" feature will be pretty welcome there.

但是,C ++迭代器仍然不能单独存在":它们必须成对使用才有用.因此,即使使用自动"功能,也还是需要一口气:

But still, a C++ iterator can't live "alone": they have to come in pairs to be useful. So, even with "auto", it's still a mouthful:

auto begin = make_transform_iterator(construct<std::string>('*', _1), 
    make_filter_iterator(_1 > 2, vec.begin())
);
auto end = make_transform_iterator(construct<std::string>('*', _1), 
    make_filter_iterator(_1 > 2, vec.end())
);

避免使用lambda会使事情变得冗长但可管理:

Avoiding the use of lambda makes things verbose, but manageable:

struct MakeStringOf{
    MakeStringOf(char C) : m_C(C){}
    char m_C;

    std::string operator()(int i){return std::string(m_C, i);}
};

struct IsGreaterThan{
    IsGreaterThan(int I) : m_I(I){}
    int m_I;

    bool operator()(int i){return i > m_I;}
};

typedef boost::filter_iterator<
   IsGreaterThan, 
   std::vector<int>::iterator
> filtered;

typedef boost::transform_iterator<
   MakeStringOf, 
   filtered
> filtered_and_transformed;

filtered_and_transformed begin(
    MakeStringOf('*'), 
    filtered(IsGreaterThan(2), vec.begin())
);

filtered_and_transformed end(
    MakeStringOf('*'), 
    filtered(IsGreaterThan(2), vec.end())
);

(尚未)Boost.RangeEx库在这方面很有前途,因为它允许将两个迭代器合并在一个范围内.像这样:

The (not-yet)Boost.RangeEx library is promising in this respect, in that it allows to combine the two iterators in a single range. Something like:

auto filtered_and_transformed = make_transform_range(
    make_filter_range(vec, _1 > 2),
    construct<std::string>('*', _1)
);

这篇关于类似于C ++ LINQ的迭代器操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆