【问题标题】:C++11: Range-looping vector from the second element?C++11:来自第二个元素的范围循环向量?
【发布时间】:2015-11-03 09:13:42
【问题描述】:

我有一个std::vector<std::string> v;(已初始化)。如何使用 range-for 循环访问除第一个元素(索引为零)以外的所有元素。对于所有元素:

for (const string & s: v)
    process(s);

可以使用范围表达式来代替v如何编写范围表达式以跳过第一个元素(或跳过前n个元素)

我知道如何使用v.begin() + 1 和使用经典循环来获得效果。我正在寻找新的、更易读的、推荐的替代方法。可能类似于 Python 切片? ...喜欢:

for s in v[1:]:
    process(s)

【问题讨论】:

  • 一种方法是使用所需元素制作一个新向量,然后循环遍历。或者你可以使用std::for_each:en.cppreference.com/w/cpp/algorithm/for_each
  • 你不能。基于范围的循环并不是每个问题的解决方案。只需使用普通循环即可。
  • 正如@GargAnkit 所述,您可以使用所需元素制作一个新向量。您可以使用向量构造函数将其作为循环声明的一部分。所以for (auto&& i : std::vector<std::string>(v.begin()+1,v.end()))。演示here。虽然不如你展示的python示例那么整洁。
  • stackoverflow.com/questions/25652505/…,它有很好的模板来解决一般问题。

标签: c++11 for-loop stdvector


【解决方案1】:

在范围进入标准库之前,您不会比普通 C++ 中的普通 for 循环更好:

for(auto i = begin(v) + 1, e = end(v); i !=e; ++i)
    // Do something with *i

【讨论】:

  • @CashCow 因为问题是关于将范围弯曲成形状,我假设是纯 C++。我已经看到足够多的 Boost 知道,如果你向它扔足够多的模板,没有什么是不可能的;)
  • @pepr 当 C++ 有范围时我会回来的。 *邪恶的笑声*
  • @Quentin:好吧,你不应该像在你的图标上那样咀嚼韭菜(除非你真的那么蓝)。它让你太邪恶了(就像一些素食者一样);)顺便说一句,我喜欢你的 ++i 例子。许多程序员会写 i++。
  • @pepr 高级韭菜咀嚼蓝......呃......东西,知道如​​何增加他们的迭代器!
  • 是的,我很困惑 :))))
【解决方案2】:

创建一个包装器,让 begin() 和 end() 返回正确的迭代器,然后您可以将其用作第二个参数。

#include <iostream>
#include <vector>

template< typename Collection >
class FromNth
{
    Collection& coll_;
    size_t offset_;

public:
    FromNth( Collection& coll, size_t offset )
        : coll_( coll ), offset_( offset )
    {
    }

    // will nicely resolve to const_iterator if necessary
    auto begin() const -> decltype( coll_.begin() ) 
       { return coll_.begin() + offset_; }

    auto end() const -> decltype( coll_.end() )
       { return coll_.end(); }
};

template< typename Collection >
FromNth<Collection> makeFromNth( Collection& collection, size_t offset )
{
     return FromNth<Collection>( collection, offset );
}

template< typename Collection >
auto begin( const FromNth<Collection> & wrapper ) -> decltype( wrapper.begin() )
{   
   return wrapper.begin();
}

template< typename Collection >
auto end( const FromNth<Collection> & wrapper ) -> decltype( wrapper.end() )
{  
   return wrapper.end();
}

int main()
{
   std::vector< int > coll { 2, 3, 5, 7, 11, 13, 17, 19, 23 };

   for( auto x : makeFromNth( coll, 1 ) )
   {
       std::cout << x << '\n';
   }
   return 0;
}

请注意,如果输入的大小小于偏移量,我的 fromNth“开始”是未定义的行为。 (如果它相等,那么它是明确定义的并且开始 == 结束)。因此,请先检查尺寸。

注意:如果您使用的是最新版本的 boost,那么 iterator_range 可能已经为您提供了类似于我的“FromNth”的“集合”。

for( auto const& s : boost::make_iterator_range( v.begin() + 1, v.end() ) )
{
    process( s );
}

注意:上面的代码使用 C++11 GNU 4.8.3 在 CodingGround 上运行。 (虽然那个网站很慢)。从 C++14 开始,您将不需要 ->decltype 语句(在 C++11 中模板需要这些语句)。

输出:

sh-4.3$ g++ -std=c++11 -o main *.cpp
sh-4.3$ main
3
5
7
11
13
17
19
23 

【讨论】:

  • 感谢您的信息!我期待已经有一些像这样的标准代码(我找不到);)
猜你喜欢
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-03
相关资源
最近更新 更多