IT Share you

루프 변수가없는 C ++ 11 범위 기반 for 루프

shareyou 2021. 1. 7. 19:56
반응형

루프 변수가없는 C ++ 11 범위 기반 for 루프


C ++에서는 특정 횟수만큼 반복해야하지만 반복 변수는 필요하지 않습니다. 예를 들면 :

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

"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 루프를 작성하는 더 우아한 방법이 있는지 궁금합니다.


이 그것을 할 수있는 방법이 될 수 있지만 수 있습니다 매우 훨씬 더 우아한 것 의심한다. 그 첫 번째 루프에있는 것은 이미 루프 변수의 범위 / 수명을 제한하는 올바른 방법입니다.

사용하지 않는 변수 경고를 무시하거나 (결국 문제 가있을 있다는 컴파일러의 표시 일뿐 ) 컴파일러 기능 (사용 가능한 경우)을 사용하여 해당 시점에서 경고를 해제합니다.

이것은 #pragma환경 따라 어떤 종류의 경우 가능할 수 있으며 일부 구현에서는 다음과 같은 작업을 수행 할 수 있습니다.

for (int x = 0; x < 10; ++x) {
    (void)x;

    // Other code goes here, that does not reference "x".
}

void함수 본문에서 사용되지 않는 매개 변수에 사용되는 트릭을 보았습니다 .


선언 된 루프 변수를 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));

이보기 에 살고 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적분에 대한 반복 유형의 범위를 생성 하는 범위 반복기 (내가 호출 함 )를 작성합니다 (기본값은 std::size_t). 그런 다음 다음을 입력하십시오.

for( auto _:index_range(10) )

변수 ( _) 를 사용 하지만 매우 혼란스러워 보입니다.

또 다른 미친 접근법은 파이썬과 유사한 생성기를 만드는 것입니다. 반복 가능 범위를 취하고 반환하는 함수를 생산하는 발전기 래퍼 작성 std::optional상의 value_type범위가 까다로운되지 않습니다.

그러면 다음을 수행 할 수 있습니다.

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;

또는 함수 작성

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";
    }
}

산출:

굉장
굉장
굉장
굉장
굉장

다음은 데모입니다.

Note: This is assuming the range specifier is a compile-time constant, so if you have to use a variable make sure it is validly marked constexpr.


There isn't any way to make a range based for work for simply iterating over several numbers.

C++11 range-based loops require a ranged expression which may be:

  • an array or
  • a class having either
    • Member functions begin() and end() or
    • available free functions begin() and end() (via ADL)

In addition to that: A range based for produces some overhead:

for ( for_range_declaration : expression ) statement

expands to

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

Where begin_expr and end_expr are obtained via array inspection or begin() / end() pairs.

I don't think this gets any "cleaner" than a simple for-loop. Especially with respect to performance. No calls, just a plain loop.

The only way I can figure out to make it more elegant (where elegant is clearly subject to my opinion) is by using a size or unsigned type here:

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

In my opinion you misuse the range-based loop. The range-based loop should be used when the logic is: "for each element in the collection do something". The whole idea is to get rid of the index variable since it isn't important. If you have a collection, you should instrument it with the necessary APIs to enable range-based iteration. If you don't have a collection, you have no business to use range-based loop (actually, that's what the compiler implies in not-so-informative way). In this situation a normal for/while loop is the natural choice.


Already best answered in https://stackoverflow.com/a/21800058/1147505 : how to define an UNUSED macro to be used throughout your codebase, which suppresses this warning. In a portable way.


You could use the STL together with a lambda expression.

#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;});
}

This approach also works for arbitrary containers such as vectors or lists. Let vector<int> a, then you'd call a.begin() and a.end(). Note that you can also use a function pointer instead of a lambda expression.

The above preserves your notion of using a foreach, while not complaining about an unused parameter.


this works in GCC and clang and any compiler that supports the gnu attributes:

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

and should compile in any c++11 compiler but may not suppress the warning if the compiler doesn't recognise the gnu attributes.


To join the contest:

#include <iostream>
#include <boost/range/irange.hpp>
using namespace std;
using namespace boost;

namespace {
    template<typename T> inline void 
    unused(const T&) {}
}

int main() {
    for (auto&& i : irange(0,10)) {
        unused(i);
        cout << "Something" << endl;
    }
    return 0;
}

ReferenceURL : https://stackoverflow.com/questions/17711655/c11-range-based-for-loops-without-loop-variable

반응형