2013년 독서 목록
c++ template explicit specialization
클래스 내부에서 멤버 함수를 explicit specialization하는 코드를 추가했더니 컴파일 오류가 난다. 컴파일러는 g++ 4.7.3이다.작성한 코드는 아래와 같은 구조다.namespace foo {class bar {template void baz() {} // base templatetemplate <> void baz() {} // explicit specialization, 여기서 컴파일 오류!};}원인을 찾아보려고 stackoverflow 등등을 뒤져서 조합한 내용을 정리해본다. 내가 의문점을 가진 순서대로이다.1. 왜 컴파일 오류가 나는가?c++ 표준에 의하면 (14.7.3.2), (멤버든 아니든) explicit specialization은 해당 template이 선언된 namespace 안에서 선언되어야 한다. 클래스 멤버라면 해당 클래스가 정의된 namespace 내에서 선언되어야 한다.예를 들자면foo.hpp:namespace foo {class bar {template void baz() {}; // base template};}foo.cpp:namespace foo {template<> void bar::baz() {} // explicit specialization, 컴파일 성공!}위와 같이 baz()에 대한 explicit specialization은 namespace foo 안에 있어야 한다는 얘기다.2. 그럼 왜 클래스 안에 정의하면 안되는가?사실 1번 설명은 처음 발생한 컴파일 오류와는 별 관계가 없어 보인다. 컴파일 실패/성공 코드는 explicit specialization을 클래스 정의 밖으로 빼낸 점만 다르기 때문이다.그렇다면 c++ 표준에서 클래스 내부는 namespace scope에 해당하지 않는다고 - 클래스 자체는 namespace 안에 정의되어 있음에도 불구하고 - 유추할 수 있겠다. 실제로 클래스 내부에 explicit specialization을 정의하고 컴파일하면 g++은 non-namescope에 정의하였다는 오류를 뱉는다.3. 클래스 안에 namespace를 정의하면 어떨까?그렇다면 아예 클래스 정의 안에 namespace를 정의하면 그 안에 explicit specialization을 할 수 있지 않을까? 하는 생각에 시도해 보았으나 컴파일이 실패한다. 이에 대한 근거를 찾다보니이런 설명이 있었다.1) c++ 표준에서 {}로 감싼 클래스는 완전한 정의가 된다. (9.2.2)2) 한 namespace의 멤버는 namespace의 이름으로 접근할 수 있고, namespace는 여러 곳으로 쪼개질 수 있다. (7.3.1)1)과 2)를 조합하면 클래스 내부에 namespace를 정의하는 것은 모순이다. 정의 완료된 클래스 내부를 namespace로 더 확장할 수 있다는 말이기 때문이다.이것이 100% 정확한 설명인 지는 확신할 수 없지만 꽤 논리적으로 보인다.4. 결론1, 2, 3에서 알아낸 사실을 조합해보니 왜 처음 작성한 코드가 컴파일이 안되는지 알 수 있었다.c++ 표준에 따르면1) explicit specialization은 namespace 내에 있어야 하는데, (1)2) 클래스 정의는 namespace에 해당하지 않기 때문이다. (2,3)c++ template은 항상 접할때마다 애먹이는 존재라 기왕 시간을 들여서 찾아본 내용을 정리해둔다.(태클 환영)참고 링크:1.template explicit specialization 관련 설명2.클래스 정의와 namespace 관련 설명