[英]C++11 range-based for loops without loop variable
在C ++中我需要迭代一定次数,但我不需要迭代变量。 例如:
for( int x=0; x<10; ++x ) {
/* code goes here, i do not reference "x" in this code */
}
我意识到我可以通过用lambda或命名函数替换“code goes here”来做到这一点,但这个问题特别针对for循环。
我希望C ++ 11的基于范围的for循环有助于:
for( auto x : boost::irange(0,10) ) {
/* code goes here, i do not reference "x" in this code */
}
但是上面给出了一个“未引用的局部变量”,因为我从未明确引用x。
我想知道是否有一种更优雅的方式来编写上面的for循环,以便代码不会生成“未引用的局部变量”警告。
现在编辑 ,声明的循环变量减少100%。
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));
可能有办法做到这一点,但我非常怀疑它会更优雅。 您在第一个循环中拥有的内容已经是正确的方法,限制了循环变量的范围/生命周期。
我只是忽略未使用的变量警告(它只是编译器指示某些东西可能是错误的),或者使用编译器工具(如果可用)来简单地关闭那时的警告。
某些#pragma
可能会出现这种情况,具体取决于您的环境,或者某些实现允许您执行以下操作:
for (int x = 0; x < 10; ++x) {
(void)x;
// Other code goes here, that does not reference "x".
}
我已经看到用于函数体中未使用参数的void
技巧。
假设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
),它产生一系列迭代器上的整数类型(我默认为std::size_t
)。 然后输入:
for( auto _:index_range(10) )
它使用变量( _
)但看起来非常混乱。
另一个疯狂的方法是创建一个类似python的生成器。 编写一个生成器包装器,它接受一个可迭代的范围并生成一个函数,该函数在该范围的value_type
上返回std::optional
并不棘手。
然后我们可以这样做:
auto _ = make_generator( index_range(10) );
while(_()) {
}
这也创造了一个临时变量,甚至更加迟钝。
我们可以编写一个在生成器上运行的循环函数:
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();
});
但是这两者都在函数中创建了一些临时变量,并且比上一个更加荒谬,并且依赖于C ++ 1y的功能,这些功能甚至还没有最终确定。
那些我尝试创建一个无变量的方法重复10次的东西。
但实际上,我只是做循环。
您几乎可以肯定通过键入x=x;
来阻止警告x=x;
或者写一个函数
template<typename Unused>
void unused( Unused&& ) {}
并调用unused(x);
- 使用变量x
,其名称被删除,因此编译器可能不会在内部发出警告。
试试这个:
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";
}
}
输出:
真棒
真棒
真棒
真棒
真棒
注意:这是假设范围说明符是编译时常量,因此如果必须使用变量,请确保它有效地标记为constexpr
。
没有任何方法可以使基于工作的范围简单地迭代多个数字。
C ++ 11基于范围的循环需要一个范围表达式,可能是:
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循环更“干净”。 特别是在性能方面。 没有电话,只是一个简单的循环。
我能想出的唯一方法是让它更优雅(优雅显然受我的意见影响)是在这里使用大小或无符号类型:
for(size_t x(0U); x<10U; ++x) f();
在我看来,你滥用基于范围的循环。 当逻辑是:“ 为集合中的每个元素做某事 ”时,应该使用基于范围的循环。 整个想法是摆脱索引变量,因为它并不重要。 如果您有一个集合,则应使用必要的API对其进行检测,以启用基于范围的迭代。 如果您没有集合,那么您就没有业务可以使用基于范围的循环(实际上,这就是编译器以不那么信息的方式所暗示的)。 在这种情况下,正常的for / while循环是自然的选择。
最好在https://stackoverflow.com/a/21800058/1147505中解答:如何定义要在整个代码库中使用的UNUSED宏,这会抑制此警告。 以便携的方式。
您可以将STL与lambda表达式一起使用。
#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()
。 请注意,您还可以使用函数指针而不是lambda表达式。
以上内容保留了使用foreach的概念,同时不抱怨未使用的参数。
这适用于GCC和clang以及任何支持gnu属性的编译器:
for( [[gnu::unused]] auto x : boost::irange(0,10) ) {
并且应该在任何c ++ 11编译器中编译,但如果编译器无法识别gnu属性,则可能无法抑制警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.