심각한 뒷북인지 모르겠는데,
본인은 비주얼 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 사무엘