41. 두 단계 이름 조회와 의존 이름, typename/template/this-> 명시자

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C++
// [주제] 템플릿의 두 단계 이름 조회(two-phase name lookup)와 의존 이름,
//        typename / template / this-> 명시자
//
// 템플릿은 "정의 시점"과 "인스턴스화 시점"의 두 단계로 이름을 조회한다.
// 아래 코드는 올바르게 컴파일되도록 typename / template / this-> 를 붙여 두었다.
//
// [과제]
//  1) Derived::foo 에서 base 멤버 useBase() 를 왜 그냥 useBase() 가 아니라
//     this->useBase() (또는 Base<T>::useBase()) 로 불러야 하는가?
//     명시자를 빼면 어느 단계에서 무슨 에러가 나는지 설명하라.
//  2) typename C::value_type 에서 typename 을 빼면 컴파일러는 그 이름을
//     무엇으로 해석하며 왜 에러인가?
//  3) p->template get<0>() 에서 template 키워드가 왜 필요한가?
//     빼면 `<` 를 어떻게 파싱하게 되는가?
//  4) 두 단계 조회에서 "의존 이름(dependent name)"과 "비의존 이름"이 각각
//     언제 조회되는지, ADL 이 어느 단계에 관여하는지 설명하라.

#include <vector>
#include <cstddef>

template <class T>
struct Base {
    void useBase() {}
};

template <class T>
struct Derived : Base<T> {
    void foo() {
        // (1) 의존 기반 클래스의 멤버 → this-> 로 의존 이름화해야 조회됨
        this->useBase();
    }
};

template <class C>
typename C::value_type firstElem(const C& c) {
    // (2) C::value_type 은 의존 이름 → typename 으로 "타입"임을 명시
    typename C::value_type v = c.front();
    return v;
}

struct Holder {
    template <int N>
    int get() const { return N; }
};

template <class P>
int callGet(P* p) {
    // (3) 의존 이름의 멤버 템플릿 → template 키워드로 disambiguate
    return p->template get<0>();
}

int main() {
    Derived<int> d;
    d.foo();

    std::vector<int> v{10, 20, 30};
    int f = firstElem(v);
    (void)f;

    Holder h;
    int g = callGet(&h);
    (void)g;
    return 0;
}
내 리뷰 · C++
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.