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)
输出应该是一个范围,类似于std :: pair,类似于boost :: multi-index
中方法的返回值在stl中有这样的东西吗?或者类似的任何可靠的图书馆?
答案 0 :(得分: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;
}
}
然后你称之为:
vector<Foo> myfoos;
vector<vector<Foo>::iterator> results;
select_iterators(myfoos.begin(), myfoos.end(), std::back_inserter(results), some_comparator);
您可以使用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); }
);
}
2)不是预先测试所有值并在某处写入结果,而是定义一个迭代器,每次递增时它会超过原始范围,直到找到下一个匹配。 Boost提供了两种方法:boost::filter_iterator
和boost::adaptors::filter
。所以你可以写:
auto results = boost::adaptors::filter(myfoos, some_comparator);
然后,无论您想对结果做什么,都可以从results.begin()
迭代到results.end()
,就好像它是一个容器一样。它不是容器,它不满足整个容器界面。它满足由Boost定义的接口,名为Range,相当于“可以迭代”。它实际上只是myfoos
的过滤视图,因此不会复制或移动任何Foo
对象。
答案 1 :(得分:4)
如果你可以修改你的向量std::partition将是你的选择。在这里你怎么称呼它:
std::vector<int>::iterator p =
std::partition(v.begin(), v.end(), you_predicate);
您在v.begin()
和p
之间回答谎言。
答案 2 :(得分:2)
您可能正在寻找boost::range
boost::range
实际上是一对迭代器,用于分隔容器的一系列元素。该库包括各种算法,这些算法返回范围内的范围(例如容器中等效值的范围,以及用户提供的等价仿函数)。
答案 3 :(得分:1)
template<typename ForwardIterator, typename OutputIterator, typename UnaryPredicate>
void find_elements(ForwardIterator first, ForwardIterator last, OutputIterator out, UnaryPredicate pred)
{
while(first != last)
{
if(pred(*first))
*out++ = first;
++first;
}
}
要记住的事情:
1。)您说您希望您的容器为iterator
而不是const_iterator
。类型将与传递给函数的开始和结束范围相同。例如,const_iterator
容器的类型为const
,如果您使用const_iterator
和vector::cbegin
,则类型也为vector::cend
,并且无法编译如果您使用不同的迭代器,例如vector::begin
和vector::cend
。
2。)向量经常失去迭代器有效性,因此使用这些迭代器时要小心。例如,如果添加到向量,则此函数返回的每个迭代器都可能无效。要防止这种情况发生,请使用其他容器(例如列表)或使用vector::reserve
。
3.)前向迭代器必须是支持++的东西,并且在解除引用时,与InputIterator具有相同的类型(例如vector<int>::iterator
)。在递增它之后它也必须保持有效的迭代器,否则函数将毫无意义。输出迭代器必须到达一个有足够空间的位置来容纳所有找到satsify pred
的迭代器。如果您事先不知道空格,可以使用std::back_inserter
中的<iterator>
与已定义container::push_back
的容器,并且会根据需要增加。
以下是对功能的测试,以便您了解其工作原理。
int main()
{
vector<string> ss = {"hi", "yog", "engils", "pog"};
// Define a predicate
auto isSizeThree = [](string const &s)
{
return s.size() == 3;
};
// example one: Somehow I know how many satisfy the predicate. I just don't know where they are.
vector<vector<string>::iterator> answer(2);
find_elements(begin(ss), end(ss), begin(answer), isSizeThree);
// Check answer
cout << "Test 1" << endl;
for(auto entry : answer)
cout << *entry << endl;
// Example two: I don't know how many there will be (more typical). If I use a continer with stuff in it - it will stack right on the back of it!
find_elements(begin(ss), end(ss), back_inserter(answer), isSizeThree);
// Check answer (has the answer from test 1 still in it)
cout << "Test 2" << endl;
for(auto entry : answer)
cout << *entry << endl;
// Example Three: Same as test 2 but clear the ansewr vector first.
answer.clear();
find_elements(begin(ss), end(ss), back_inserter(answer), isSizeThree);
// Check answer
cout << "Test 3" << endl;
for(auto entry : answer)
cout << *entry << endl;
}