2011-08-29 2 views
0

나는 다소 단순하다. 상상해 보니 CRTP에 대한 질문이지만 대답을 찾을 수없는 것 같다. 아마, 그것은 매우 간단하기 때문에, 아무도 그것을 요구할 생각을하지 않았습니다. 나는이 개념을 처음 사용합니다. 너무 웃지 마세요.). 내가 잘못된 typedef typename _THelpee::T Th;을 언급하는 경우typedef의 CRTP 관련 컴파일러 오류

template< typename tT > 
struct TBase 
{ 
    typedef tT T; 
}; 

template< typename tTBase > 
struct TTraitsBase 
{ 
    typedef typename tTBase::T T; 
}; 

template< typename tTHelpee, typename tTTraits > 
struct THelper 
{ 

    typedef typename tTTraits::T T; 
    typedef typename tTHelpee::T Th; /* This generates a compiler error: 
             'T' not being a member of TDerived<tT> */ 
    T Foo(void) 
    { 
    return static_cast< tTHelpee* > (this)->mVal; 
    } 
}; 

template< typename tT > 
struct TDerived : TBase<tT> , THelper< TDerived<tT> , TTraitsBase< TBase<tT> > > 
{ 
using TBase<tT>::T; 
    T mVal; 
}; 

int main() 
{ 
TDerived<int>::T lTmp = -1; 
TDerived<int> lObj; 

lObj.mVal = -1; 
std::cout << lObj.Foo() << std::endl; 

return 0; 
} 

모든 컴파일 : 여기

은 (STL 컨테이너와 유사한 무언가를하기위한 시도의 그것의 종류) 코드입니다. 그리고 저를 혼란스럽게합니다 : 컴파일러가 typedef typename _THelpee::T Th;을 좋아하지 않는다면, 왜 그것이 static_cast< _THelpee* > (this)->mVal을 통과하게합니까? 나는 그것이 TDerived을 인스턴스화 할 때 THelper을 인스턴스화 할 수 없다는 것과 관련이 있지만 확실한 이해가 없다고 가정합니다. 누군가, 제발, 여기에서 일어나는 일에 대한 간략한 설명 및/또는 참고 문헌을 줄 수 있습니까? 고맙습니다.

편집 : '_T'접두어가 제거되었습니다.

+2

[_ 및 대문자로 시작하는 식별자는 예약되어 있습니다] (http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-ac) -identifier/228797 # 228797). – Flexo

+0

자신의 식별자에 밑줄 - 자본을 사용하지 마십시오. 금지되어 있습니다. –

답변

2

암시의 멤버 함수 정의를 인스턴스화하지 않는 클래스를 인스턴스화. 클래스 템플릿의 각 멤버는 명시 적 인스턴스화를 사용하지 않는 한 사용 된 경우에만 인스턴스화됩니다.

처음에 암시 적으로 인스턴스화하는 것은 main의 첫 번째 줄에 TDerived<int>입니다. 이를 인스턴스화하기 위해 컴파일러는 TDerived 템플릿을 조회하여 몇 가지 종속 기본 클래스가 있음을 확인하고이를 인스턴스화하려고 시도합니다. TBase<int>은 문제없이 인스턴스화됩니다. 그러나 THelper< TDerived<int>, TTraitsBase< TBase<int> > >을 인스턴스화하려고 시도 할 때 구성원 TDerived<int>::T을 얻으려고했지만 TDerived<int>은 여전히 ​​불완전한 유형입니다.

인스턴스화 THelper<...>도 멤버 함수 int Foo()이 있지만 해당 정의의 의미를 평가하지 않습니다. int THelper<...>::Foo()TDerived<int> 완전한 형태입니다 인스턴스화, 그래서 문제가 없다 당신이 main에서 lObj.Foo()를 부르는 시간으로

.

+0

고마워요! 그것은 그것을 분명히 설명합니다. 분명히 함수를 인스턴스화하는 함수를 인식하지 못했습니다. 나는'TDerived'가 실제로 불완전하다는 것을 알았지 만'Foo()'가이 경우에 아무런 문제도 일으키지 않은 이유를 알 수있었습니다. 이제는 분명합니다. – lapk

+0

'TDerived'에있는'typedefs '에 액세스하려면'Telits' 또는 가능한'TBase' 템플릿 매개 변수를'THelper '에 사용하는 것이 정상적인 것으로 간주됩니까? 아니면 그것을하는 "표준"방법이 더 있습니다 (주제에 대한 언급이 크게 감사 할 것입니다)? 그리고 이전의 설명에 다시 한 번 감사드립니다. – lapk

2

게시 된 코드에 몇 가지 문제가 있습니다. 나는 의도를 이해할 수 없기 때문에 내가 잘못 발견 한 것을 열거 할 것입니다. 당신이 TDerived<_T>의 몸을 정의 할 때

template< typename _T > 
struct TDerived : TBase<_T> , THelper< TDerived<_T> , TTraitsBase< TBase<_T> > > 
             ^^^^^^^^^^^^^^ it's incomplete 

이 IMO, 당신은 아무것도에 매개 변수와 동일하게 사용하지 않아야합니다 : 불완전한 유형를 사용

(1).

(2) 부적절한 유형 정의.

using TBase<_T>::T; 

해야한다,

typedef typename TBase<_T>::T T; 
+1

템플릿 매개 변수가 불완전한 유형 이어도 괜찮습니다 (CRTP의 경우 항상 그렇습니다). 그러나 모든 불완전 유형과 마찬가지로 해당 유형의 유효한 사용에는 제한이 있습니다. – aschepler

+0

입력 해 주셔서 감사합니다, iammilind. 제 생각에 aschepler가 대답했습니다. 내가 여기에서 새로운 이래로 나는 규칙을 어기고 토론에 들어가기를 꺼린다. – lapk

1

난 당신이 (한 것으로, 본질적으로) 당신의 CRTP에 순환 종속성이 말하고 싶지만,하지만 그 의미 기본 템플릿 클래스 ISN 매개 변수 클래스를 사용할 수 있습니다. 왜냐하면 매우 매개 변수 클래스가 아직 정의되지 않았기 때문입니다. Base<T>이 인스턴스화 된 시점에서 여전히 불완전한 유형입니다.

그래서,이 OK입니다 :

template <typename T> struct Base 
{ 
    T * impl; // incomplete type is OK 
}; 

class Foo : public Base<Foo> { /* ... */ }; 

을하지만이되지 않습니다 :

template <typename T> struct Base 
{ 
    T x; // need to know T, but T depends on Base<T>! 
}; 
+0

감사. 나는 당신이 그의 대답에서, 더 적은 세부 사항으로 aschepler와 같은 것을 말하고 있다고 가정합니다. – lapk