访问基于范围的循环(如for_each)中的std::map迭代器
Accessing std::map iterators inside range based loop like for_each
由于基于范围的循环很流行,所以我试图找出如何以高效的方式编写以下代码,即使用基于范围的环路。
但是,请随意重组代码和/或提出另一种构造,这可能被认为是处理std::map 的连续密钥的更好方法
C++11兼容的答案是首选,但为了了解情况,请随时推荐boost或C++14 中的任何内容
void mapRangeLoop()
{
std::map<std::string, std::vector<int>> infoMap;
// **** Piece of Code to be improved BEGIN *********
std::for_each(infoMap.rbegin(), infoMap.rend(), [&infoMap](auto& it) {
auto prev = std::prev(infoMap.find(it.first)); // <---I would like to avoid use of find() to get the iterator
if (prev != infoMap.end() && isSubString(prev->first, it.first))
for (auto& p : prev->second)
processVectors(p, it.second);
});
// **** Piece of Code to be improved END *********
// Same thing could be achieved through traditional for loop like this
for (auto it = infoMap.rbegin(); it != infoMap.rend(); ++it)
{
auto prev = std::next(it);
if (prev != infoMap.rend() && isSubString(prev->first, it->first))
for (auto& p : prev->second)
processVectors(p, it->second);
}
}
//Just for completeness
bool isSubString(const std::string& s1, const std::string& s2)
{
// returns true or false based on some logic
}
void processVectors(const int i, std::vector<int>& vec)
{
// Some logic to modify vec based on value of i
}
基于范围的循环和std::foreach
都被设计为独立于其他元素单独处理元素。如果您需要其他元素的迭代器,则需要显式地提供它:
auto next = infoMap.begin();
for(auto& prev: infoMap)
{
++next; // now points to element succeeding prev...
if(next != infoMap.end())
{
// your code...
}
}
不过,基于范围的循环不会以相反的顺序迭代,但最终的想法是一样的:
auto next = infoMap.rbegin();
std::for_each(infoMap.rbegin(), infoMap.rend(), [&infoMap, &next](auto& prev)
{
++next; // again one in advance compared to prev...
// (other direction than in above loop, though!)
if(next != infoMap.rend())
{
// your code...
}
});
不过,我个人还是会坚持经典循环;它的优点是可以将if
移出:
if(infoMap.size() >= 2)
{
for (auto next = std::next(infoMap.rbegin()); next != infoMap.rend(); ++next)
{
prev = std::prev(next);
// your code...
}
}
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class It>
range_t<It> range( It s, It f ) { return {std::move(s), std::move(f)}; }
这是支持任意范围上的CCD_ 3循环的最小类型。
接下来我称之为索引迭代:
template<class V>
struct indexing_iteroid {
using self=indexing_iteroid;
V value;
// * just returns a copy of value
V operator*() const& { return value; }
V operator*()&&{ return std::move(value); }
// ++ forwards to value:
self& operator++() {
++value;
return *this;
}
self operator++(int) {
auto r = *this;
++*this;
return r;
}
// == compares values:
friend bool operator==(self const& lhs, self const& rhs) {
return lhs.value == rhs.value;
}
friend bool operator!=(self const& lhs, self const& rhs) {
return lhs.value != rhs.value;
}
};
如果您愿意,您可以将其扩展到一个完整的输入迭代器;在实践中,超出此范围的类别需要一个后备容器。
但是这个iteroid对于for(:)
循环来说已经足够好了,这些循环不是根据迭代器类别来指定的,而是根据特定的操作来指定的。
template<class It>
range_t< indexing_iterator<It> > index_over_range( range_t<It> r ) {
return {{r.begin()}, {r.end()}};
}
这需要一个范围,并在其中的迭代器上创建一个范围
for (auto it : index_over_range( range( infoMap.begin(), infoMap.end() ) ) )
{
}
现在这是一个for(:)
循环,它访问infoMap
中的每个迭代器,而不是infoMap
中的每个元素。
我们可以用更多的样板来清理一下
namespace adl {
namespace it_details {
using std::begin; using std::end;
template<class X>
auto adl_begin( X&& x )
-> decltype( begin( std::forward<X>(x) ) )
{ return begin( std::forward<X>(x) ); }
template<class X>
auto adl_end( X&& x )
-> decltype( end( std::forward<X>(x) ) )
{ return end( std::forward<X>(x) ); }
}
template<class X>
auto begin( X&& x )
-> decltype( it_details::adl_begin( std::forward<X>(x) ) )
{ return it_details::adl_begin( std::forward<X>(x) ); }
template<class X>
auto end( X&& x )
-> decltype( it_details::adl_end( std::forward<X>(x) ) )
{ return it_details::adl_end( std::forward<X>(x) ); }
}
这给出了在std::begin
可用的上下文中调用x
上的begin
的adl::begin( x )
(和adl::end( x )
(,但begin
的参数相关查找也是如此。这几乎与for(:)
循环查找其开始/结束迭代器的方式完全匹配。
template<class C>
auto iterators_of( C& c )
-> decltype( index_over_range( range( adl::begin(c), adl::end(c) ) ) )
{ return index_over_range( range( adl::begin(c), adl::end(c) ) ); }
现在iterators_of(someMap)
将所有迭代器的范围返回到someMap
:
for (auto it : iterators_of( infoMap ) )
{
}
我们有很好的,干净高效的语法。
顺便说一句,indexing_iteroid
还可以用来创建一个计数迭代(因此对于循环访问0、1、2、3来说是一个迭代(,比如:
using counting_iteroid = indexing_iteroid<std::size_t>;
auto zero_to_ten = range( counting_iteroid{0}, counting_iteroid{11} );
for (auto x : zero_to_ten) {
std::cout << x << "n";
}
上面可能有一些打字错误。
有一类类型是indexing_iteroid
可以包装的;整数和迭代器都传递了这个概念。您可以将indexing_iteroid
增强为更接近随机访问,但由于随机访问迭代器概念的标准化方式存在缺陷,它无法使您达到比输入迭代器更高的迭代器类别。c++2a的Rangesv3可能会解决这个问题。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- .cpp和.h文件中的模板专用化声明
- 反向给定链表中的K节点
- 正在查找文档以获得PS4平台的C++中的设备信息
- enum是C++中的宏变量还是整数变量
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 将字符串存储在c++中的稳定内存中
- 文本文件中的单词链表
- 递归函数计算序列中的平方和(并输出过程)
- 如何从C++中的依赖类型中获得它所依赖的类型
- C++中的"inline"关键字
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 用C++中的一个变量定义一个常量
- 为什么我的矢量中的项目在 C++ 中的 for-each 循环期间不会改变?
- C++:从"for each"循环中的映射中删除值
- 正在擦除for(-each)自动循环中的项目
- C++中的"for each"循环如何知道数组的长度
- 如何使c++中的for each循环函数与自定义类一起工作
- 在C++11中的一个向量上使用for each