C++ 템플릿 상속에서 베이스 클래스의 멤버에 접근하는 경우의 문제
주의 사항
이 글은 예전 블로그에서 옮겨온 오래 된 글입니다. 현재 상황과는 다를 수 있으며, 잘못 된 정보가 있을 수 있습니다.
C++ 템플릿 상속엔 골 때리는 문제가 있는데 … 바로 베이스클래스의 멤버에 접근하려면 베이스 클래스의 이름을 명시해야 한다는 것이다… 안그러면 이름을 못찾아온다 사람 상당히 귀찮게 만드는놈이라 할 수 있겠다. 보통 일반적으론 볼일이 없고 Mixin 을 이용하거나 아니면 Effective C++ 을 읽으면서 알게된다(책에는 “못찾는다” 라고 되어 있다)
간단히 말하면 이런 코드다
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
31
32
33
34
35
#include <cstdio>
void foo()
{
printf("Global Function\n");
}
template <typename T>
class Cls1
{
T Var1;
public:
void foo()
{
printf("Member Function\n");
}
};
template <typename T>
class Cls2 : public Cls1<T>
{
T Var2;
public:
void test()
{
Cls1<T>::foo();
}
};
int main()
{
Cls2<int> cls2;
cls2.test();
return 0;
}
근데 만약 명시 하지 않으면 어떻게 될까?
일단 최신의 VC++ 2012에서 돌려보자
헐…? 정확히 멤버 함수를 찾아온다. 여기엔 올리지 않겠지만 VS2005~2010 도 모두 같은 동작을 한다.
다른컴파일러에서 해보자. gcc 4.4다. 헐?! 글로벌 함수를 찾는다 (…) 이거뭥미.
그럼 최신의 C++0x를 지원하는 gcc4.7에서 해보자. 역시 전역함수를 찾는다.
표준문서는 귀찮아서 (…) 확인하지 않았지만 관련 서적 등을 보면 gcc의 동작이 맞는 것으로 보인다. 하지만 저런 코드를 짜면서 gcc 쪽 동작을 원하는 사람이 과연 있을까… 하는 생각이 든다. 일반적인 클래스를 만드는 느낌으로 당연히 멤버함수가 호출 될 것이라고 생각 하지 않을까? 이 결과를 확인하면서 C++은 당최 생각대로 움직여 주지 않는 매저키스트 들을 위한 언어란 누군가의 말이 귓가에 맴돈다 (…)
결론 : EC++에 나온대로 그냥 제대로 포커스 지정 하자 (…) 야!
PS. gcc 에서는 저렇게 두가지 모두 있는 경우가 아니라 전역 foo 함수가 없는 (즉 이름을 찾을 수 없는) 경우에는 당연히 이름을 찾지 못해 에러를 내는데, 이 경우 컴파일 옵션에 -fpermissive 를 추가 하는 것으로 멤버함수로의 연결이 가능하다(워닝은 뜬다) 단 전역 foo 함수가 존재 할 경우 저 옵션을 그냥 무시하고 그냥 전역 함수로 연결해 버린다.
PS2. 혹시 LLVM-clang 을 사용할 수 있는 환경에 계신분은 어떤 결과가 나오는지 알려주시면 좋겠다.