C++의 for each, in 키워드

심각한 뒷북인지 모르겠는데,
본인은 비주얼 C++에서 이런 문법이 가능하다는 걸 아주 최근에야 알게 되었다.

DATA container[N];

for each(DATA elem in container) {
    do_with(elem);
}

저건 언어 차원에서 제공하는 새로운 문법이기 때문에 STL <algorithm>의 for_each 함수와는 다르다.

배열을 순회하기 위한 별도의 임시 변수(일회용 int i나 거추장스러운 포인터)를 선언할 필요 없이, 코드를 굉장히 깔끔하게 만들 수 있어서 좋다. 이것의 주 용도는 C++을 상당한 고수준 언어로 끌어올린 C++/CLI 환경이지만, 네이티브 환경에서도 정적 배열과 STL 컨테이너 정도에서는 아주 요긴하게 쓰일 수 있다.

DATA가 int 같은 아주 기본적인 자료형이라면 그냥 저렇게 써 주면 되고, 개당 수십~수백 바이트씩 하는 무거운 구조체라면 const DATA&를 하면 된다. 그리고 순회 중인 배열 자체의 데이터를 루프 안에서 고쳐야 한다면 물론 DATA&라고 써 주면 된다.
저건 C++11 같은 급도 아니고, 생각보다 굉장히 오래 된 비주얼 C++ 2005에서부터 지원되기 시작했다고 한다.

컴파일러가 언어 표준에 없는 변칙 문법이나 키워드를 지원하는 것은 특정 CPU나 운영체제에 종속적인 기능을 추가로 제공하기 위해서이다.
하지만 for each는 그런 범주에 속하지 않으며, 전통적인 C/C++ 언어의 토큰 나열과 비교했을 때 문법도 굉장히 이질적이다. 그럼에도 불구하고 비주얼 C++이 이것을 제공하는 것이 신기하기 그지없다.

그리고 또 하나 생각할 점은, 저기서 each와 in은 문맥 의존적인 임시 예약어(키워드)라는 것이다. for 다음에 이어졌을 때만 키워드이며, 다른 곳에서는 사용자가 each나 in을 일반적인 변수/함수명으로 얼마든지 쓸 수 있다는 뜻.

언어 설계 차원에서 C/C++은 원래 임시 예약어라는 게 없는 언어이다. 한번 예약어로 찜해진 단어는 그 어떤 곳에서도 명칭으로 결코 쓰일 수 없다. 다른 구문이나 수식을 파싱하는 데는 문맥 의존적인 어려운 문법이 많지만, 예약어 식별만은 단순하게 만들려고 했는가 보다.

그 반면, 파스칼은 begin, end, if, for 같은 단어야 절대적인 예약어이겠지만 forward(함수 전방 선언용)를 포함해 몇몇 키워드는 일정 문맥에서 별도의 의미를 갖는 임시 예약어이다. 그리고 객체지향 개념이 추가된 오브젝트 파스칼의 경우 virtual 같은 함수 modifier, 그리고 클래스 내부에서 public/protected 같은 멤버 접근성 modifier도 임시 예약어이다. C++은 그렇지 않다.

비주얼 C++은 for each, in뿐만 아니라 abstract, override, delegate 등 몇몇 비표준 임시 예약어를 더 두고 있기도 한데, 이것은 대개가 C++/CLI용이고 네이티브 환경에서는 쓰일 일이 별로 없다. 일반적인 경우라면 비표준 확장 예약어는 앞에 __를 붙여서 명칭 충돌의 여지를 없앤 뒤에 절대적인 예약어로 추가하는 게 관행일 텐데, 저것들은 그렇게 하지 않았다.

끝으로, for each, in에다가 2차원 배열을 넘겨 주면 어떻게 될까 궁금해서 시도를 해 봤는데, 이때도 각 원소들이 하나씩 순서대로 순회되더라.
각 배열을 배열의 포인터로 받으면서 1차원적으로 순회되지는 않는가 보다.

비주얼 C++ 2010은 인텔리센스 컴파일러와 실제 컴파일러의 동작이 서로 다르기라도 했는지, IDE에서는 이때 each 변수가 2차원 배열과 서로 호환이 되지 않는다고 빨간줄 에러를 뱉은 반면, 실제 컴파일은 됐다.
2012에서는 그것이 개선되어 IDE에서도 빨간줄이 생기지 않는다.

Posted by 사무엘

2013/02/16 08:17 2013/02/16 08:17
, , ,
Response
No Trackback , 4 Comments
RSS :
http://moogi.new21.org/tc/rss/response/796

Trackback URL : http://moogi.new21.org/tc/trackback/796

Comments List

  1. 김진 2013/02/16 12:01 # M/D Reply Permalink

    C#에만 있는 문법인 줄 알았는데 C++에서도 쓸 수 있었군요. 배열 순회도 될 텐데, C#에서는 배열의 배열int[2][3]과 2차원배열int[2,3]을 구별하니까 그 영향이 있을 것 같네요.
    자바에도 이게 있는데 코드를 깔끔하게 만들어 주기도 하지만, 엉뚱한 인덱스 변수를 쓰거나 값이 배열 범위 바깥으로 벗어나는 사태를 원천봉쇄한다는 점이 좋더군요.

    1. 사무엘 2013/02/16 19:33 # M/D Permalink

      오랜만에 뵙네요. ^^
      네, 아주 C#스러운 문법이죠. 아주 안전하고 편리하긴 하나, 남발하면 나의 C++ 코드도 점점 MS 컴파일러에 종속될 것 같습니다.
      그나저나 C#은 배열의 배열과 다차원 배열을 모두 표현할 수 있는 게 마치 Ada 언어와 비슷하다는 생각이 들었습니다. ^^

    2. 김진 2013/02/18 01:08 # M/D Permalink

      찾아보니 C++11표준에 이게 있었네요. gcc나 clang에서는 이런 형식으로 쓰더군요:
      DATA container[N];
      for (auto elem : container) {
      do_with(elem);
      }
      표준이니 앞으로는 모든 컴파일러에서 지원하겠네요.^^

    3. 사무엘 2013/02/18 10:00 # M/D Permalink

      보충 설명에 감사드립니다. ^^
      C++에서 그런 문법을 정식 도입하려면 저렇게 기호를 쓰지 each, in 같은 거추장스러운 영단어 나열을 쓰지는 않을 겁니다. 그건 C++의 철학이 아니라 생각됩니다.
      다만, for의 한참 다음에 ; 이 나오느냐 : 이 나오느냐를 계속 토큰을 살펴봐야 전통적인 for인지 새로운 for인지 파악이 될 테니, 파싱은 좀 어려울 것 같습니다.

Leave a comment
« Previous : 1 : ... 1511 : 1512 : 1513 : 1514 : 1515 : 1516 : 1517 : 1518 : 1519 : ... 2204 : Next »

블로그 이미지

그런즉 이제 애호박, 단호박, 늙은호박 이 셋은 항상 있으나, 그 중에 제일은 늙은호박이니라.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2024/11   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

Site Stats

Total hits:
2984165
Today:
1902
Yesterday:
1381