C ++ 11基于范围的循环,没有循环variables

在C + +我需要迭代一定的次数,但我不需要一个迭代variables。 例如:

for( int x=0; x<10; ++x ) { /* code goes here, i do not reference "x" in this code */ } 

我意识到我可以通过用“lambda”或“named”函数replace“code goes here”来做到这一点,但是这个问题是关于for循环的。

我希望C ++ 11的基于范围的循环将有助于:

 for( auto x : boost::irange(0,10) ) { /* code goes here, i do not reference "x" in this code */ } 

但上面给出了“未引用的局部variables”,因为我从来没有明确地引用x。

我想知道是否有更优雅的方式来编写上面的循环,以便代码不会生成“未引用的局部variables”警告。

可能有办法做到这一点,但我非常怀疑它会更优雅。 你在第一个循环中已经是正确的方法,限制循环variables的范围/生命周期。

我会简单地忽略未使用的variables警告(这只是编译器指出可能是错误的一个指示),或者使用编译器工具(如果可用)来简单地closures此时的警告。

现在编辑声明为100%的循环variables。

 template <typename F> void repeat(unsigned n, F f) { while (n--) f(); } 

使用它作为:

 repeat(10, f); 

要么

 repeat(10, [] { f(); }); 

要么

 int g(int); repeat(10, std::bind(g, 42)); 

http://ideone.com/4k83TJ上;查看

假设10是一个编译时间常量…

 #include <cstddef> #include <utility> template<std::size_t N> struct do_N_times_type { template<typename Lambda> void operator()( Lambda&& closure ) const { closure(); do_N_times_type<N-1>()(std::forward<Lambda>(closure)); } }; template<> struct do_N_times_type<1> { template<typename Lambda> void operator()( Lambda&& closure ) const { std::forward<Lambda>(closure)(); } }; template<> struct do_N_times_type<0> { template<typename Lambda> void operator()( Lambda&& closure ) const { } }; template<std::size_t N, typename Lambda> void do_N_times( Lambda&& closure ) { do_N_times_type<N>()( std::forward<Lambda>(closure) ); }; #include <iostream> void f() { std::cout << "did it!\n"; } int main() { do_N_times<10>([&]{ f(); }); } 

要不就

 int main() { do_N_times<10>(f); } 

其他荒谬的方法:

编写一个范围迭代器(我称之为我的index ),它产生一系列迭代器 – 整型types(我默认为std::size_t )。 然后键入:

 for( auto _:index_range(10) ) 

它使用一个variables( _ ),但看起来非常混乱。

另一个疯狂的方法是创build一个类似python的生成器。 编写一个生成可迭代范围的生成器包装器,并生成一个函数,该函数返回该范围的value_typestd::optional

我们可以这样做:

 auto _ = make_generator( index_range(10) ); while(_()) { } 

这也创造了一个临时variables,甚至更加钝。

我们可以编写一个在发生器上运行的循环函数:

 template<typename Generator, typename Lambda> void While( Generator&& g, Lambda&& l ) { while(true) { auto opt = g(); if (!opt) return; l(*opt); } } 

我们这样称呼:

 While( make_generator( index_range(10) ), [&](auto&&){ f(); }); 

但是这两个函数都在函数中创build了一些临时variables,而且比最后一个更可笑,而且依赖于C ++ 1y的特性,这个特性还没有最终确定。

那些我试图创造一个variablesless的方式重复10次的东西。

但是,真的,我只是做循环。

你几乎可以肯定的通过键入x=x;来阻止这个警告x=x;

或者写一个函数

 template<typename Unused> void unused( Unused&& ) {} 

并呼叫unused(x); – 使用了variablesx ,并将其名称放入内部,因此编译器可能不会在内部警告您。

所以试试这个:

 template<typename Unused> void unused( Unused&& ) {} for(int x{};x<10;++x) { unused(x); f(); } 

这应该压制警告,而且实际上很容易理解。

实际上有一种方法可以使这项工作。 所有你需要做的是返回一个std::array ,其长度由你提供的常量指定:

 template <int N> using range = std::array<int, N>; int main() { for (auto x : range<5>()) { std::cout << "Awesome\n"; } } 

输出:

真棒
真棒
真棒
真棒
真棒

这里是一个演示。

注意:这是假定范围说明符是一个编译时常量,所以如果你必须使用一个variables,确保它被有效标记为constexpr

没有任何方法可以使工作范围的基础上迭代几个数字。

C ++ 11基于范围的循环需要一个范围expression式,可能是:

  • 一个数组或
  • 有一个类也有
    • 成员函数begin()end()
    • 可用的免费函数begin()end() (通过ADL)

除此之外:基于范围的产生一些开销:

 for ( for_range_declaration : expression ) statement 

扩展到

 range_init = (expression) { auto && __range = range_init; for ( auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin ) { for_range_declaration = *__begin; statement; } } 

begin_expr和end_expr是通过数组检查或begin() / end()对获得的。

我不认为这比简单的for循环更清洁。 特别是在性能方面。 没有电话,只是一个简单的循环。

唯一的方法,我可以弄清楚,使其更优雅(其中雅致明显受我的意见)是通过在这里使用大小或无符号types:

 for(size_t x(0U); x<10U; ++x) f(); 

你可以使用STL和一个lambdaexpression式。

 #include <algorithm> #include <iostream> int main() { int a[] = {1,2,3,4,5,6}; std::for_each(std::begin(a), std::end(a), [](int){std::cout << "Don't care" << std::endl;}); } 

这种方法也适用于任意容器,如向量或列表。 让vector<int> a ,然后调用a.begin()a.end() 。 请注意,您也可以使用函数指针而不是lambdaexpression式。

上面保留了使用foreach的概念,而不是抱怨一个未使用的参数。

在我看来,你滥用基于范围的循环。 当逻辑是“ 为集合中的每个元素做某事 ”时,应该使用基于范围的循环。 整个想法是摆脱索引variables,因为它并不重要。 如果你有一个集合,你应该使用必要的API来启用基于范围的迭代。 如果你没有一个集合,你没有业务使用基于范围的循环(实际上,这是编译器以不那么信息的方式所暗示的)。 在这种情况下,正常的/ while循环是自然的select。

这在GCC和clang以及任何支持gnu属性的编译器中都有效:

 for( [[gnu::unused]] auto x : boost::irange(0,10) ) { 

并且应该在任何c ++ 11编译器中进行编译,但如果编译器不能识别gnu属性,则可能不会抑制警告。