2010-12-02 3 views
7

부스트와 Qt로 작업하는 행복한 사람들이 있습니다. 내 "임베디드"프로젝트에서는 집에서 만든 컨테이너 클래스를 사용해야합니다. OK, 충분히 불평.C++의 Foreach 구현, 가난한 사람의 접근 방식

나는 그렇게 쉽고 자체에 포함 된 foreach 문을 구현하기 위해 시도했다 : 그것은 연산 []과의 getSize() 메소드가 문자열 목록을 반복

#define ForEachString(S,C) TString S;\ 
     for (int i=0; i<C.GetSize() && (!!(&(S=C[i]))); ++i ) 

. 예 :

TStringList tables; 
ForEachString(table, tables) 
{ 
    //do sth. with tab. 
} 

원인은 각 컨테이너 유형마다 자체 매크로가 필요하다는 것입니다. 따라서 내 질문 : 컨테이너 자체 독립적 인 포함 할 수 있습니까 (모든 필수 내용 내에서 매크로 정의)?

감사합니다, 발렌틴

+7

대답은 "예"이며 설명은 [여기] (http://www.artima.com/cppsource/foreach.html)에서 찾을 수 있습니다. –

+0

그냥 STL과 같은 메소드 이름을 따르십시오. – werehuman

+2

표준이 아니며 가독성을 크게 높이 지 못하고 중복 정의 같은 문제를 숨길 수 있습니다. –

답변

6

은 아마도 당신은 T 타입에 파라미터를 설정할 수 :

#define ForEach(T,S,C) T S;\ 
    for (int i=0; i<C.GetSize() && (!!(&(S=C[i]))); ++i ) 

TStringList tables; 
ForEach(TString, table, tables) 
{ 
    //do sth. with tab. 
} 
+0

좋아, 가장 실용적인 접근 방법 인 것 같다. –

+0

이것은 Talagrand가 지적한 것처럼 하나의 표현식이 아닙니다. ++ i)'(TS, int i = 0; i

+1

Meh, [BOOST_FOREACH] (http://stackoverflow.com/questions/4339589/foreach-implementation-in-ca-poor-mans-approach/4339813#4339813)는 불필요한 매개 변수를 피하기 때문에 더 시원합니다. – Brian

2

매크로가 위험하다. 고려 :

if (<condition>) 
    ForEachString(table, tables) 
    { 
     // do something 
    } 

또한 S가 엔클 로징 범위에 포함됩니다. 따라서 동일한 블록에서 두 개의 ForEachString 호출을 수행 할 수 없습니다. 당신이 출혈 가장자리 컴파일러가있는 경우

range-based for-loops는 단지 일부를 입력합니다, decltype(C[0]) S;

TString S;을 대체 또는 수, C++ 0x로, 다시 C++ 0X

의 일부입니다 매크로의 :

#define ForEachString(T, S, C) T S; ... 
+0

힌트를 보내 주셔서 감사합니다. 그러나 예를 들어 컴파일 오류가 발생하므로 위험하지는 않습니다. 첫 번째 매개 변수의 이름이 다른 경우 동일한 범위에서 두 개의 'foreach'가 실행됩니다. Unfortanutely, C++ 0x는 프로젝트에서 사용되지 않습니다. –

2

부스트 라이브러리에는이 작업을 수행하는 BOOST_FOREACH라는 foreach-like 매크로가 구현되어 있습니다. 이것은 컨테이너 독립적이며 원시 배열 및 C 스타일 문자열에서도 작동 할 수 있습니다. 구현은 무서운 것 (타입 인트로 스펙 션을위한 수많은 미친 템플릿 기계)에 불과하지만 그물 결과는 빠르고, 가늘고, 평균적으로 널리 사용됩니다. 이 here에 대한 자세한 정보를 확인할 수 있습니다.

희망이 도움이됩니다.

-1

이 매크로를 작성하는 것이 목표라면, Eric Niebler가 foreach를 구현하는 방법에 대한 설명을 읽어 보시고, Johannes Schaub - litb (this)가 가리키는 것이 좋습니다. 이 문제를 해결하려고 할 때 발생하는 모든 함정에 대해 자세하게 설명합니다.

foreach 매크로가 작동하는 것이 주된 관심사라면 문서화되어 Boost에 Eric Niebler가 BOOST_FOREACH으로 제출하십시오.

커뮤니티 위키. 요하네스가 말한 것을 반복하고 있기 때문입니다.

+0

-1 : 먼저 읽어주십시오. Boost는 많은 프로젝트 (예 : 많은 자동차)에서 "사용할 수 없습니다". 가장 공식적인 이유는 안정적이지 않다는 것입니다. 나는 진짜 이유가 의심 스럽다. 많은 프로젝트 리더들은 충분히 친숙하지 않아서 부스트를하고있다. –

4

나는 _j_와 이상한 행동은 루프 내에서 break의 균형에 필요한이 하나

#define ForEachString(S,C) \ 
    if(bool _j_ = false) ; else 
    for (int _i_ = 0; _i_ < C.GetSize() && !_j_; ++_i_, _j_ = !_j_) 
     for(S = C[_i_]; !_j_; _j_ = true) 

TStringList tables; 
ForEachString(TString table, tables) 
{ 
    //do sth. with table 
} 

를 추천 할 것입니다._i__j_과 같은 이름을 사용하면 사용자의 로컬 루프 변수를 방해하지 않을 수 있습니다.

+0

두 번째 for 루프는 S로 다음 값을 가져 오는 데 사용됩니까? 실제로 컨테이너가 포인터를 포함하고 0 포인터가 유효하면 (!! (& (S = C [i])))는 false를 반환 할 수 있으므로 더 나은 해결책 인 것 같습니다. 이 경우 반복은 멈출 것이다 :-((제 경우 op []는 const refs를 반환합니다. 그래서이 시나리오를 먼저 고려하지 않았습니다) –

0
#define MY_CONTAINER(a, b) a b; \ 
    typedef a::iterator b##_itr; 
#define for_each(itr, a) for(a##_itr itr = a.begin(); itr != a.end(); ++itr) 

MY_CONTAINER(vector<int>, vnVec); 
vnVec.push_back(2); 
vnVec.push_back(3); 
vnVec.push_back(10); 

for_each(itr, vnVec) 
    cout << *itr << endl; 
관련 문제