C++0x 미리보기 2, 오른쪽 꺾음괄호들(>>)

류광, 2007/11/19 01:13
템플릿 구문에서 연속된 오른쪽 꺾음괄호들(>>)의 처리 방식이 바뀝니다.

이전 글에 나온 빈칸은 단지 코드의 가독성에 영향을 미쳤을 뿐이지만, 이번 글의 빈칸은 코드의 컴파일 가능 여부를 결정합니다.

템플릿을 써본 C++ 프로그래머는 누구나 다음과 같은 현상을 겪어 보았을 것입니다. (미리보기 1과 마찬가지로 예제 코드는 관련 문서들에서 가져온 것입니다.)

#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // 오류

두 번째 문장에서 컴파일 오류가 나는 것은, 컴파일러가 >>를 두 개의 >가 아니라 하나의 >> 연산자로 인식하기 때문입니다. 이는 사실 좀 당황스럽고 짜증나는 일입니다. "이 정도는 컴파일러가 알아서 처리해 줘야 하는 거 아닌가요"[1]라는 불평이 나올만도 합니다.

그렇다고 이 문제가 단지 기존 표준 제정자들이 당연한 뭔가를 간과했기 때문인 것만은 아닙니다. 컴파일러가 >>를 >>라는 단일한 연산자로 인식하는 것은 소위 ‘maximum munch’라는 원칙을 따른 것입니다. 이 최대한 물어뜯기 원칙은 예를 들어 i+++j가 i+ (++j)가 아니라 (i++) +j 로 해석되게 하는 것으로, C++ 소스 코드의 파싱을 좀 더 간단하게 만드는 중요한 원칙입니다. 따라서 단순히 ‘이제부터는 >>가 컴파일 오류를 일으키지 않게 하자’라고 선언하는 것으로 문제가 해결되지는 않습니다. 적어도 템플릿 구문에 대해서는 이러한 원칙과는 다른 새로운 해석 규칙을 만들어야 합니다.

제안자가 제시한 새로운 해석 규칙은 다음과 같습니다:

규칙

만일 왼쪽 꺾음괄호(<)가 하나라도 살아 있으면(즉, 그에 상응하는 >가 아직 나오지 않았다면), 이후의 >>는 단일한 >> 연산자가 아니라 두 개의 개별적인 >들로 간주한다. 단, 괄호쌍이나 대괄호쌍 안에 있는 >>는 예외이다.

std::vector<std::vector<bool>>의 경우 >>가 나온 상황에서 두 개의 <가 ‘살아’ 있으므로 >>는 두 개의 >들로 간주됩니다. ‘단’으로 시작하는 문구는 다음과 같은 상황에서 중요해 집니다.

Y<X<6>>1>> x4;

프로그래머의 의도는 6을 오른쪽으로 한 자리 이동한 값을 X의 템플릿 인수로 지정한 것이지만, 위와 같은 규칙 하에서 첫 >>는 두 개의 개별적인 >로 간주되며, 따라서 컴파일 오류가 납니다. 이를 방지하기 위해서는 해당 표현식을 명시적인 괄호쌍으로 감싸야 합니다. 즉:

Y<X<(6>>1)>> x4;

이는 현재 표준에서 A<X>Y>가 오류이고 반드시 A<(X>Y)>라고 써줘야 하는 것과 마찬가지 방식입니다.

그런데 새 규칙이 완벽하지는 않습니다. 제안서에는 기존의 적법한 코드의 의미가 새 규칙 때문에 달라지는 예가 나오는데, 다음과 같습니다.

#include <iostream>
template<int I> struct X {
  static int const c = 2;
};
template<> struct X<0> {
  typedef int c;
};
template<typename T> struct Y {
  static int const c = 3;
};
static int const c = 4;
int main() {
  std::cout << (Y<X<1> >::c >::c>::c) << '\n';
  std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}

현재의 표준에서 두 번째 cout 문의 첫 c는 전역 변수 c가 되지만, 새 규칙 하에서는 Y 템플릿의 정적 멤버 c가 됩니다. 따라서 현재 표준에서는 두 cout 문이 다른 결과를 내지만, 새 규칙 하에서는 같은 결과를 냅니다.

제안자는 코드의 의미가 바뀌는 것은 위의 예처럼 상당히 복잡하고 작위적인 경우에서이고, 실제 현업 코드에서 새 규칙 때문에 코드의 의미가 바뀌는 일은 드물 거라고 주장합니다. 제안이 통과된 것으로 봐서 아마도 표준 위원회의 여러 멤버들도 같은 생각이었던 것 같습니다.

제안서에는 이 글에서 언급하지 않은 다른 대안들이라던가 예들이 있는데 읽어 보시면 재미있을 것입니다.


[1] 물론 정적/강한 형식 언어에서 뭔가를 '알아서 처리하는' 컴파일러는 좀 위험합니다. 바람직한 방식은 오류로 처리하되 '빈칸이 필요합니다'라고 친절히 조언을 하는 것이겠죠).

top
트랙백 0 : 의견 # + 4

Trackback Address :: http://occamsrazr.net/tt/trackback/172

comments powered by Disqus

(2013년 11월 10일자로 블로그에도 DISQUS 시스템을 도입했습니다. 기존 의견의 수정, 삭제, 댓글 추가는 여전히 가능합니다.)

  1. A2 2007/11/19 01:34 PERMALINKMODIFY/DELETE REPLY

    지난번에 이어서 좋은 정보 감사드립니다.

  2. 류광 2007/11/22 19:22 PERMALINKMODIFY/DELETE REPLY

    다음 편도 기대해 주세요~

  3. kwak101 2007/11/26 14:31 PERMALINKMODIFY/DELETE REPLY

    저도 봤는데, 심정적으로는 동감합니다만 기술적으로는 동감하지 않습니다. 최대 잘라먹기 규칙에 대한, 왠지 불편한 예외규칙이 생길 필요까지는 없어 보이거든요.

  4. 류광 2007/11/26 20:29 PERMALINKMODIFY/DELETE REPLY

    일단 템플릿 끝의 >>가 골치거리이고 어떻게든 해결을 해야 한다는 점은 공감대를 이루고 있는 것 같습니다. 여기 저기 쓰이는 >를 템플릿 구문의 구분자로 선택했던 것 자체가 원인이겠지만 사실 다른 기호를 생각하기도 힘들고요.

    제안서의 선택은 특히 A<X>Y>를 A<(X>Y)>로 표기해야 하는 현재 표준과 일관된다는 점에서 제일 나은 대안인 것 같습니다만... 이 문제를 CFG의 관점에서 한 번 분석해 주시면 어떨까요?