如何从std :: vector或list中选择一个子集?

Jam*_*ond 10 c++ boost stl

c ++大师:

有一些有用的c ++ stl算法,如find或search.但是,似乎他们只返回一个单一的交互者.

如果我想为STL容器做一个SQL样式'select'怎么办?比方说,一个矢量(可能会扩展到列表或地图).就像是

std::pair<vector::iterator, vector::iterator> select(std::vector::iterator begin, std::vector::iterator end, Comparor equal_to)
Run Code Online (Sandbox Code Playgroud)

输出应该是一个范围,类似于std :: pair,类似于boost :: multi-index中方法的返回值

在stl中有这样的东西吗?或者类似的任何可靠的图书馆?

Ste*_*sop 5

你基本上有两种方法:

1)你在上面的注释中说的东西,将结果写入(迭代器指向)迭代器的容器.这看起来像这样:

template <typename ForwardIterator, typename OutputIterator, typename UnaryPredicate>
void select_iterators(ForwardIterator first, ForwardIterator last, 
                      OutputIterator out, UnaryPredicate pred) {
    while (first != last) {
        if pred(*first) *out++ = first;
        ++first;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你称之为:

vector<Foo> myfoos;
vector<vector<Foo>::iterator> results;
select_iterators(myfoos.begin(), myfoos.end(), std::back_inserter(results), some_comparator);
Run Code Online (Sandbox Code Playgroud)

您实际上可以select_iterators使用copy_if和其他算法来定义boost::counting_iterator,但是当直接实现如此简单时,我认为这不值得.它看起来像:

template <typename ForwardIterator, typename OutputIterator, typename UnaryPredicate>
void select_iterators(ForwardIterator first, ForwardIterator last, 
                      OutputIterator out, UnaryPredicate pred) {
    std::copy_if(
        boost::make_counting_iterator(first), 
        boost::make_counting_iterator(last),
        out,
        [&](ForwardIterator it) { return pred(*it); }
    );
}
Run Code Online (Sandbox Code Playgroud)

2)不是预先测试所有值并在某处写入结果,而是定义一个迭代器,每次递增时都会在原始范围内前进,直到找到下一个匹配.Boost提供了两种方法,boost::filter_iterator并且boost::adaptors::filter.所以你可以写:

auto results = boost::adaptors::filter(myfoos, some_comparator);
Run Code Online (Sandbox Code Playgroud)

然后,无论你想对结果做什么,你都可以迭代results.begin()results.end()它就像是一个容器.它不是容器,它不满足整个容器界面.它满足由Boost定义的接口,名为Range,相当于"可以迭代".它实际上只是一个过滤后的视图myfoos,因此不会Foo复制或移动任何对象.