문제

대부분의 STL 컨테이너에서 작동하는 C++에서 자주 사용하는 'foreach' 매크로가 있습니다.

#define foreach(var, container) \
  for(typeof((container).begin()) var = (container).begin(); \
      var != (container).end(); \
      ++var)

('typeof'는 gcc 확장자입니다.) 다음과 같이 사용됩니다.

std::vector< Blorgus > blorgi = ...;
foreach(blorgus, blorgi) {
  blorgus->draw();
}

지도의 값을 반복하는 비슷한 것을 만들고 싶습니다.아마도 "foreach_value"라고 부르세요.그래서 글을 쓰는 것보다

foreach(pair, mymap) {
  pair->second->foo();
}

나는 쓸 것이다

foreach_value(v, mymap) {
  v.foo();
}

두 가지 변수를 선언해야 하기 때문에 이 작업을 수행하는 매크로를 만들 수 없습니다.반복자와 값 변수(위의 'v').gcc 확장을 사용하더라도 for 루프의 초기화에서 이를 수행하는 방법을 모르겠습니다.foreach_value 호출 직전에 이를 선언할 수 있지만 그렇게 하면 동일한 범위에 있는 foreach_value 매크로의 다른 인스턴스와 충돌하게 됩니다.반복자 변수 이름에 현재 줄 번호를 접미사로 붙일 수 있다면 작동하겠지만 어떻게 해야 할지 모르겠습니다.

도움이 되었습니까?

해결책

두 개의 루프를 사용하여 이 작업을 수행할 수 있습니다.첫 번째는 컨테이너 변수의 함수인 이름을 사용하여 반복자를 선언합니다(자신의 코드와의 충돌이 걱정된다면 이를 더 보기 흉하게 만들 수 있습니다).두 번째는 값 변수를 선언합니다.

#define ci(container) container ## iter
#define foreach_value(var, container) \
    for (typeof((container).begin()) ci(container) = container.begin(); \
         ci(container) != container.end(); ) \
        for (typeof(ci(container)->second)* var = &ci(container)->second; \
             ci(container) != container.end(); \
             (++ci(container) != container.end()) ? \
                 (var = &ci(container)->second) : var)

동일한 루프 종료 조건을 사용하면 외부 루프는 한 번만 발생합니다(운이 좋으면 최적화됩니다).또한 맵이 비어 있으면 반복자에서 ->second를 호출하는 것을 피하세요.이는 내부 루프의 증분에서 삼항 연산자에 대한 동일한 이유입니다.마지막에는 다시 참조되지 않으므로 var를 마지막 값에 그대로 둡니다.

ci(컨테이너)를 인라인할 수 있지만 매크로를 더 읽기 쉽게 만드는 것 같습니다.

다른 팁

당신은 찾고있을 것입니다 BOOST_FOREACH - 그들은 이미 당신을 위해 모든 작업을 완료했습니다!

직접 굴러 가고 싶다면 C ++의 어느 곳에서나 블록을 선언 할 수 있습니다.

// Valid C++ code (which does nothing useful)
{
  int a = 21; // Which could be storage of your value type
}
// a out of scope here
{ 
  int a = 32; // Does not conflict with a above
}

STL 변환 함수도 비슷한 일을 합니다.

인수는 다음과 같습니다(순서대로).

  1. 컨테이너의 시작을 지정하는 입력 반복기
  2. 컨테이너의 끝을 지정하는 입력 반복기
  3. 출력을 저장할 위치를 정의하는 출력 반복기(for-each와 유사한 내부 변환의 경우 #1의 입력 반복기를 전달하기만 하면 됩니다)
  4. 각 요소에 대해 수행할 단항 함수(함수 개체)

매우 간단한 예를 들어 다음과 같이 문자열의 각 문자를 대문자로 표시할 수 있습니다.

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

int main(int argc, char* argv[]) {
    std::string s("my lowercase string");
    std::transform(s.begin(), s.end(), s.begin(), toupper);
    std::cout << s << std::endl; // "MY LOWERCASE STRING"
}

대안으로는 축적하다 함수 개체에 대한 호출 사이에 일부 값이 유지되도록 허용합니다. 축적하다 의 경우처럼 입력 컨테이너의 데이터를 수정하지 않습니다. 변환.

당신은 부스트 라이브러리?그들은 foreach 매크로 구현 아마도 당신이 작성하는 어떤 것보다 더 강력할 것입니다...그리고 또 있다 transform_iterator 원하는 것의 두 번째 추출 부분을 수행하는 데 사용할 수 있는 것 같습니다.

안타깝게도 정확히 말씀드릴 수는 없습니다 어떻게 나는 C++을 충분히 모르기 때문에 그것을 사용합니다 :) 이번 구글 검색 몇 가지 유망한 답변이 나타납니다. comp.lang.c++.moderated, BoostTransform_iterator 사용 사례.

Boost::For_each가 가장 좋은 방법입니다.멋진 점은 그들이 실제로 제공하는 매크로 BOOST_FOREACH()를 코드에서 실제로 호출하고 싶은 항목으로 래핑하고 #define할 수 있다는 것입니다.대부분의 사람들은 오래된 "foreach"를 선택하지만 다른 상점에서는 코딩 표준이 다를 수 있으므로 이것이 그러한 사고 방식에 적합합니다.Boost에는 C++ 개발자를 위한 다른 유용한 기능도 많이 있습니다!사용할만한 가치가 있습니다.

로컬 변수와 포인터에서 작동하는 foreach()의 몇 가지 변형과 루프 내에서 요소 삭제를 방지하는 추가 버전을 사용하여 작은 Foreach.h 도우미를 만들었습니다.따라서 내 매크로를 사용하는 코드는 다음과 같이 멋지고 편안해 보입니다.

#include <cstdio>
#include <vector>
#include "foreach.h"

int main()
{
    // make int vector and fill it
    vector<int> k;
    for (int i=0; i<10; ++i) k.push_back(i);

    // show what the upper loop filled
    foreach_ (it, k) printf("%i ",(*it));
    printf("\n");

    // show all of the data, but get rid of 4
    // http://en.wikipedia.org/wiki/Tetraphobia :)
    foreachdel_ (it, k)
    {
        if (*it == 4) it=k.erase(it);
        printf("%i ",(*it));
    }
    printf("\n");

    return 0;
}

산출:

0 1 2 3 4 5 6 7 8 9
0 1 2 3 5 6 7 8 9

나의 Foreach.h 다음 매크로를 제공합니다:

  • foreach() - 포인터에 대한 일반 foreach
  • foreach_() - 지역 변수에 대한 일반 foreach
  • foreachdel() - 루프 내 삭제 검사가 포함된 foreach 버전, 포인터 버전
  • foreachdel_() - 루프 내 삭제 검사가 포함된 foreach 버전, 지역 변수 버전

그들은 확실히 나에게 도움이 됩니다. 나는 그들이 당신의 삶을 좀 더 쉽게 만들어 주기를 바랍니다 :)

이 질문에는 두 부분이 있습니다.어떻게든 (1) 지도에 대해 반복자(또는 오히려 반복 가능한 시퀀스)를 생성해야 합니다. 가치 (키가 아님), (2) 매크로를 사용하여 많은 상용구 없이 반복을 수행합니다.

가장 깨끗한 해결책은 부스트 범위 어댑터 파트 (1)과 부스트 포리치 (2) 부분.매크로를 작성하거나 반복자를 직접 구현할 필요는 없습니다.

#include <map>
#include <string>
#include <boost/range/adaptor/map.hpp>
#include <boost/foreach.hpp>

int main()
{
    // Sample data
    std::map<int, std::string> myMap ;
    myMap[0] = "Zero" ;
    myMap[10] = "Ten" ;
    myMap[20] = "Twenty" ;

    // Loop over map values
    BOOST_FOREACH( std::string text, myMap | boost::adaptors::map_values )
    {
        std::cout << text << " " ;
    }
}
// Output:
// Zero Ten Twenty

mymap 유형을 템플릿 매개변수로 사용하고 * 및 ->를 오버로드하여 값에 대한 반복자처럼 작동하는 템플릿 클래스를 정의할 수 있습니다.

#define foreach(var, container) for (typeof((container).begin()) var = (container).begin(); var != (container).end(); ++var)

C++에는 typeof가 없습니다.이건 어떻게 컴파일되고 있나요?(물론 휴대성은 좋지 않습니다)

나는 내 자신을 구현했다 foreach_value 를 기반으로 Boost foreach 암호:

#include <boost/preprocessor/cat.hpp>
#define MUNZEKONZA_FOREACH_IN_MAP_ID(x)  BOOST_PP_CAT(x, __LINE__)

namespace munzekonza {
namespace foreach_in_map_private {
inline bool set_false(bool& b) {
  b = false;
  return false;
}

}
}

#define MUNZEKONZA_FOREACH_VALUE(value, map)                                  \
for(auto MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) = map.begin();      \
        MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();)       \
for(bool MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true;       \
      MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) &&               \
      MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it) != map.end();          \
      (MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue)) ?              \
        ((void)++MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)) :          \
        (void)0)                                                              \
  if( munzekonza::foreach_in_map_private::set_false(                          \
          MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue))) {} else    \
  for( value = MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_it)->second;      \
        !MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue);              \
        MUNZEKONZA_FOREACH_IN_MAP_ID(_foreach_in_map_continue) = true)        

예를 들어 다음과 같이 코드에서 사용할 수 있습니다.

#define MUNZEKONZA_FOREACH_VALUE foreach_value

std::map<int, std::string> mymap;
// populate the map ...

foreach_value( const std::string& value, mymap ) {
  // do something with value
}

// change value
foreach_value( std::string& value, mymap ) {
  value = "hey";
}
#define zforeach(var, container) for(auto var = (container).begin(); var != (container).end(); ++var)

typeof()가 없으므로 다음을 사용할 수 있습니다.

decltype((container).begin()) var 
decltype(container)::iterator var
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top