考虑以下示例:
(?:StatementId: \[?)(.*)(?:\]?, .*UserId: )([0-9]*)
是否可以在类中创建一个函数来返回同样驻留在类中的std :: vector中的项,但是跳过nullptr项?或任何其他项目。我在想一些lambda函数的使用会使这个工作,但我不知道如何。
注意我希望它在不重新创建任何其他新向量的情况下高效并返回。最好是在C ++ 11中工作。
答案 0 :(得分:3)
您可以使用boost::adaptors::filtered
(或ranges::view::filter
):
// pipe version
for (Item* i : foo.items | filtered([](Item* i){return i;})) {
// ...
}
// function version
for (Item* i : filter(foo.items, [](Item* i){return i;})) {
// ...
}
如果您想要挑战,这是更容易编写的适配器之一。你只需要一个迭代器类型,它比++
的{{1}}前向稍微复杂一些。
但是使用operator++()
语句可能更容易,不是吗?
if
答案 1 :(得分:2)
这是使用高阶函数和lambdas的替代方法,它抽象了过滤逻辑。它不需要任何额外的依赖。
template <typename TContainer, typename TF>
auto for_nonnull_items(TContainer&& container, TF f)
{
for(auto&& i : container)
{
if(i == nullptr) continue;
f(i);
}
return f;
}
std::vector<int*> example{/*...*/};
for_nonnull_items(example, [](auto ptr)
{
// do something with `ptr`
});
通过调用for_nonnull_items(this->items, /*...*/)
内的foo
,您可以实现更好的界面:
foo.for_nonnull_items([](auto ptr)
{
// do something with `ptr`
});
答案 2 :(得分:0)
从std::iterator
派生使自定义迭代器变得相当简单。在这种情况下,我实现了一个forward_only迭代器。根据需要添加更多功能。
#include <iterator>
template<class Iter>
struct non_null_forward_iterator : std::iterator<std::forward_iterator_tag, typename Iter::value_type>
{
using value_type = typename Iter::value_type;
non_null_forward_iterator(Iter i, Iter last) : iter_(i), last_(last)
{
seek();
}
value_type operator*() const {
return *iter_;
}
non_null_forward_iterator& operator++() {
++iter_;
seek();
return *this;
}
void seek()
{
while (iter_ != last_) {
if (*iter_)
break;
++iter_;
}
}
bool operator==(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
bool operator!=(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
Iter iter_;
Iter last_;
};
template<class Container>
auto non_null_range(const Container& cont)
{
using underlying_iter_type = typename Container::const_iterator;
using iter_type = non_null_forward_iterator<underlying_iter_type>;
struct X {
iter_type begin() const { return begin_; }
iter_type end() const { return end_; }
iter_type begin_;
iter_type end_;
};
return X {
iter_type(cont.begin(), cont.end()),
iter_type(cont.end(), cont.end())
};
}
struct Item {};
std::ostream& operator<<(std::ostream& os, const Item& item)
{
return std::cout << "an item";
}
int main()
{
std::vector<Item*> items = { nullptr, new Item(), new Item(), nullptr };
for (auto p : non_null_range(items))
{
std::cout << *p << std::endl;
}
}
预期产出:
an item
an item
答案 3 :(得分:0)
This answer另一个SO问题提供了一个适用于此处的解决方案。这个问题的公认答案没有。
这在C ++ 14中实现了一个通用的过滤器帮助器。
for( auto ptr: filter([](auto&& x){return x!=nullptr;})( test ) )
将遍历test
的元素,使x!=nullptr
。
在C ++ 11中执行此操作主要包括填写返回类型。最后的filter
函数是例外,它返回一个lambda,这在C ++ 11中是不可能的,并且在lambda中使用auto&&
。
许多C ++ 11编译器支持lambdas的auto
参数。那些没有的,你可以将返回的filter
lambda及其参数折叠到filter
函数本身,然后写出繁琐的返回值。
C ++ 2x TS具有协同作用,这使得这一点变得微不足道。 The code will look roughly like:
std::generator<Item*> non_null_items() {
for( Item* i : items )
if ( i ) co_return i;
}
作为班上的一种方法。
这反映了类似的C#和python语法。