C++类似LINQ的迭代器操作

Eam*_*nne 12 c++ linq iterator functional-programming

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

linq作为linq-consumer(即对我而言)的真正优势不在于表达树(操作起来很复杂),而是我可以轻松地混合和匹配各种功能.做的等价物.Where,.Select.SelectMany, .Skip.Take.Concat存在C++ -风格的迭代器?

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

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

k06*_*06a 8

我正在研究(C#LINQ)类似C++头的库.

这是:http://code.google.com/p/boolinq/

我想得到任何反馈......

更新:

这是boolinq 2.0的新链接:https://github.com/k06a/boolinq

所有源代码都基于单头文件 - https://github.com/k06a/boolinq/blob/master/boolinq/boolinq.h

这是超短的:大约60种不同的操作不到800行!


小智 6

我想推荐P-Stade.Oven库供您参考.这是一个强大的增强库,用于STL范围,具有许多类似LINQ的功能,包括.Where,.Select .Skip .Take和.Concat等效.


Éri*_*ant 4

我没有使用 LINQ 的具体经验,但Boost.Iterator库似乎接近您所指的内容。

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

LINQ“哪里”映射到make_filter_iterator

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

LINQ“选择”映射到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())
Run Code Online (Sandbox Code Playgroud)

它们可以组成:

//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())
)
Run Code Online (Sandbox Code Playgroud)

然而,这有一些烦人的事情:

  • 返回的类型make_xxx_iterator(some_functor, some_other_iterator)xxx_iterator<type_of_some_functor, type_of_some_iterator>
  • 使用 boost::bind、lambda 或 phoenix 创建的函子类型很快就会变得难以管理且编写起来很麻烦。

这就是为什么我在上面的代码中避免将结果分配make_xxx_iterator给变量。C++0x“自动”功能在那里会很受欢迎。

但是,C++ 迭代器仍然不能“单独”存在:它们必须成对出现才能发挥作用。所以,即使有了“auto”,它仍然很拗口:

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())
);
Run Code Online (Sandbox Code Playgroud)

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

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())
);
Run Code Online (Sandbox Code Playgroud)

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

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