답변:
다음은 Josuttis 책의 인용문입니다.
뒤에
typename
오는 식별자가 유형임을 지정하기 위해 키워드 가 도입되었습니다. 다음 예제를 고려하십시오.template <class T> Class MyClass { typename T::SubType * ptr; ... };
여기
typename
에서이SubType
유형이 임을 명확히하는 데 사용됩니다class T
. 따라서ptr
유형에 대한 포인터T::SubType
입니다. 하지 않고typename
,SubType
정적 멤버 간주됩니다. 그러므로T::SubType * ptr
SubType
형식 의 값을와 곱하는 것T
입니다ptr
.
typename
하지 않습니다 (모두는 아니지만).
Stan Lippman의 BLog 게시물 은 다음과 같이 제안합니다.
Stroustrup 은 기존 클래스 키워드 를 재사용하여 기존 프로그램을 손상시킬 수있는 새 키워드를 도입하는 대신 유형 매개 변수를 지정했습니다. 새로운 키워드는 고려되지 않은 것이 아니라 잠재적 인 중단으로 인해 필요하지 않은 것으로 간주되었습니다. 그리고 최대 ISO-C ++ 표준 때까지,이 유형 매개 변수를 선언 할 수있는 유일한 방법이었다.
기본적으로 Stroustrup은 다음과 같은 이유로 표준에서 변경되는 새 키워드를 도입하지 않고 클래스 키워드를 재사용했습니다.
주어진 예로서
template <class T>
class Demonstration {
public:
void method() {
T::A *aObj; // oops …
// …
};
언어 문법 T::A *aObj;
은 산술 식으로 잘못 해석 되어 새로운 키워드가 도입됩니다.typename
typename T::A* a6;
컴파일러에게 후속 명령문을 선언으로 처리하도록 지시합니다.
키워드가 급여에 있었기 때문에 클래스 키워드를 재사용하기 로 한 원래 결정 으로 인한 혼란을 해결하지 않겠습니까 ?
우리 둘 다 가지고있는 이유
이 게시물을 살펴볼 수 있습니다. 확실히 도움이 될 것입니다.
typename
기존 키워드 class
를 같은 목적으로 사용할 수 있다면 왜 새로운 키워드가 필요한 가요?
typename
Josuttis를 인용하여 Naveen의 답변에 설명 된 것처럼 구문 분석 문제를 해결하는 데 필요했습니다. ( class
이 곳에 at을 삽입해도 효과가 없을 것이라고 생각합니다 .)이 경우 새 키워드가 허용 된 후에 만 템플릿 인수 선언 ( 또는 정의입니까? ) 에서도 허용 class
되었습니다. 오해의 소지가 있습니다.
소위 종속 유형 의 멤버 ( "템플리트 매개 변수에 종속"을 의미 함)를 참조하는 일부 상황에서 컴파일러는 결과 구조의 의미 적 의미를 모호하지 않게 추론 할 수 없습니다. (예 : 유형 이름, 데이터 멤버 이름 또는 다른 이름인지 여부). 그런 경우 컴파일러에 이름이 해당 종속 유형의 구성원으로 정의 된 유형 이름에 속한다고 명시 적으로 명시하여 상황을 명확하게해야합니다.
예를 들어
template <class T> struct S {
typename T::type i;
};
이 예에서는 typename
코드를 컴파일하는 데 필요한 키워드 입니다.
종속 유형의 템플리트 멤버 (예 : 템플리트를 지정하는 이름)를 참조하려는 경우에도 마찬가지입니다. template
다르게 배치되어 있지만 키워드를 사용하여 컴파일러를 도와야합니다.
template <class T> struct S {
T::template ptr<int> p;
};
경우에 따라 두 가지를 모두 사용해야 할 수도 있습니다.
template <class T> struct S {
typename T::template ptr<int>::type i;
};
(구문이 올바르게 있다면).
물론 키워드의 다른 역할은 typename
템플릿 매개 변수 선언에 사용됩니다.
비밀은 템플릿이 일부 유형에 특화 될 수 있다는 사실에 있습니다. 이는 또한 여러 유형에 대해 완전히 다른 인터페이스를 정의 할 수 있음을 의미합니다. 예를 들어 다음과 같이 쓸 수 있습니다.
template<typename T>
struct test {
typedef T* ptr;
};
template<> // complete specialization
struct test<int> { // for the case T is int
T* ptr;
};
왜 이것이 유용하고 실제로 유용한 지 묻습니다. 그것은 실제로 쓸모없는 것처럼 보입니다. 그러나 예를 들어 마음에 걸릴 유형이 다른보다 완전히 다른 모습 들. 분명히 유형의 유형을 다른 유형으로 변경하지는 않지만 발생할 수는 있습니다.std::vector<bool>
reference
T
reference
이제이 템플릿을 사용하여 자신 만의 템플릿을 작성하면 어떻게됩니까 test
? 이 같은
template<typename T>
void print(T& x) {
test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
그것이 유형 이라고 기대 하기 때문에 당신에게 괜찮은 것 같습니다 test<T>::ptr
. 그러나 컴파일러는 알지 못하며 실제로 표준에서 반대를 기대한다고 조언 test<T>::ptr
합니다. 유형이 아닙니다. 컴파일러에게 typename
이전 에 추가해야 할 것을 알려주려면 . 올바른 템플릿은 다음과 같습니다
template<typename T>
void print(T& x) {
typename test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
결론 : typename
템플릿에서 중첩 유형의 템플릿을 사용할 때마다 추가 해야합니다. 물론 템플릿의 템플릿 매개 변수가 해당 내부 템플릿에 사용 된 경우에만 해당됩니다.
모든 답변에서 typename
키워드가 두 가지 경우에 사용 된다고 언급 한 것 같습니다.
a) 템플릿 유형 매개 변수를 선언 할 때 예 :
template<class T> class MyClass{}; // these two cases are
template<typename T> class MyNewClass{}; // exactly the same.
그들 사이에 차이점이 없으며 정확히 동일합니다.
b) 템플릿에 중첩 종속 유형 이름 을 사용하기 전에
template<class T>
void foo(const T & param)
{
typename T::NestedType * value; // we should use typename here
}
사용하지 않으면 typename
구문 분석 / 컴파일 오류가 발생합니다.
Scot Meyers 책 Effective C ++ 에서 언급했듯이 두 번째 경우에 추가하고 싶은 typename
것은 중첩 종속 유형 이름 앞에 사용하는 예외가 있다는 것입니다 . 예외는 당신이 사용하는 경우이다 중첩 의존의 형태 이름을 A와 중 하나를 기본 클래스 또는에서 멤버 초기화 목록 , 당신은 사용하지 말아야 typename
있다 :
template<class T>
class D : public B<T>::NestedType // No need for typename here
{
public:
D(std::string str) : B<T>::NestedType(str) // No need for typename here
{
typename B<T>::AnotherNestedType * x; // typename is needed here
}
}
참고 : 사용하여 typename
두 번째 경우에 (즉, 중첩 의존의 형태 이름 앞에) 20 ++ C 때문에 필요하지 않습니다.
#include <iostream>
class A {
public:
typedef int my_t;
};
template <class T>
class B {
public:
// T::my_t *ptr; // It will produce compilation error
typename T::my_t *ptr; // It will output 5
};
int main() {
B<A> b;
int my_int = 5;
b.ptr = &my_int;
std::cout << *b.ptr;
std::cin.ignore();
return 0;
}