2012-01-03 2 views
1

다음은이 질문을 해결하기 위해 사용했던 CRTP based template code입니다 : Requiring overridden virtual functions to call base implementations. 여기에 코드를 게시 하겠지만, 코드 페이지는 길고 읽기 쉽습니다 (필요한 경우 여기에 게시 할 예정입니다). 그것은 추악하고 다소 인공적입니다. 물론 작동합니다. 그러나 처음에는 MSVC++ 및 GCC 모두에서 컴파일되지만 일부 템플릿 유형은 실제로 정의되지 않았습니다. 내가 심문하는 부분은 TBase::OnEvent 기능의 긴 내면 if(typeid(Derived(N)) != typeid(Derived(N-1)) (기호 표기법) 몇 개가 맨 위에 있습니다.컴파일러는`typeid` 연산자를 어떻게 평가합니까?

당신은하지 typdef 이러한 유형은 컴파일 오류가있을 것입니다 수 있습니다 - 당신이 얻을 것이다, 그래서 같은 긴 ...::TDerived::... 체인으로 정의되는 유형에 대한 충분한 파생 클래스가 컴파일 오류 TDerived is not defined in TBase, 올바르게, 단순히 없다. 그러나 컴파일러는 typeid을 통해 이들을 먹습니다. 디버거 MSVC++ 컴파일러 출력 (전체 기호 정보 포함)을 검사했을 때, 실제로는 어떤 클래스도 생성하지 않아야하는 모든 길이가 ...::TDerived::... 인 것으로 보입니다. typeid은 클래스 체인의 마지막 TDerived04으로 컴파일러에서 해결되었습니다. 그리고 RTTI는 클래스 체인에서이 마지막 클래스를 위해 풀려났습니다. 얼마나 많은 ...::TDerived::...이 있든 상관하지 않습니다.

MSVC++ 및 GCC 모두 (codepad.org를 통해 GCC에 액세스 할 수 있음에도 불구하고) 다음을 고려하면 다음 질문에 답할 수 있습니다. typeid의 동작을 어떻게 정의합니까? 그렇다면 왜 typedef 길이가 ...::TDerived::...이 되니 TDerived04으로 해결되지 않습니까?

편집 : 내 말은, 내가 typedefTDerived04에 해결되지 않는 행복 해요, 즉 typedef를 사용하는 사람에게 재앙이 될,하지만 왜 이러한 불일치 typeidtypedef 사이의 것?

EDIT : GCC는 TDerived04::TDerived04::TDerived04::TDerived04 lD4; 변수 선언을 허용합니다. 그리고 형식은 결국 TDerived04입니다. 스코프 해상도를 축소하는 규칙이 있습니까? 분명히 MSVC++와 GCC 모두 typeid에서 동일하게 보이지만 GCC와는 달리 MSVC++는 다른 시나리오를 처리 할 수 ​​없습니다. 컴파일러 오류가 발생하여 생성자에 대한 인수가 필요합니다.

+0

코드를 한눈에 살펴본 후 가상 함수를 "다시 구현"하려고하는 것처럼 보입니다. 또는 나는 무엇인가 놓치고 있냐? – elmo

+0

@elmo 글쎄, CRTP는 "컴파일 타임에 해결 된 가상 메커니즘"을 구현할 수 있습니다. 실제로 가상 함수와 관련된 질문에 대답하고있었습니다. 구체적으로, base-derived00-derived01 ...- derivedLast 체인의 중간 클래스에있는 모든 함수에 대한 호출을 구현하는 데 이러한 클래스 중 하나에서 실제 함수 호출을 지정하지 않고 (원래의 질문을 참조하십시오.) ... 그러나 여기에는 문제가되지 않습니다. , 그것은 단지 프레임 워크입니다. 나는'typeid' 행동에 대해 궁금합니다. – lapk

+0

[this] (http://codepad.org/OlSwkfHc)가 문제를 해결합니까? 일반적으로 나는 typeid를 디버깅 용으로 만 사용하는 것을 고려할 것이다. – elmo

답변

1

typeid을 디버깅 용 도구로 사용하지는 않습니다. C++ 표준은 실존을 보장 할뿐 실제로 무엇을해야하는지 말하지 않습니다. 이것은이 유틸리티를 인간이 읽을 수있는 클래스 이름을 인쇄하는 것 이상으로 렌더링합니다 (다른 실제적인 사용법을 알고 있다면 저를 수정하십시오).

나는 위의 것 이외에 다른 것을 유용하게 만들기 위해 너무 많은 "컴파일러가 정의한"동작이 typeid이라고 말하고 싶습니다.

해결책에 제시된 접근법에도 큰 단점이 있습니다. 추악하고 유지하기가 어렵지만, 기본 클래스는 모든 파생 클래스에 대해 알아야합니다. 이것은 상당히 큰 디자인 결함입니다.

다른 해결책은 here (코드도 원래의 질문으로 게시 됨)입니다.

TDerived04::TDerived04::TDerived04::TDerived04이 유효하다는 것은 TDerived04 클래스에서 유효하다는 것은 TDerived04라는 이름을 사용하여이 클래스/네임 스페이스를 참조 할 수 있습니다. 따라서 TDerived04 :: TDerived04는 TDerived04 클래스에서 TDerived04를 가리키는 것과 같습니다 (@MSalters는 "클래스 이름 삽입"이라고 함).

1

약 주입 된 클래스 이름과 생성자 이름 사이에 애매한 점이 있습니다. class X의 범위에서 X은 클래스 자체의 이름을 지정할 수 있지만 X::X의 생성자를 참조 할 수도 있습니다..

+0

'main'에'std :: cout << (typeid (TDerived04) == typeid (TDerived04 :: TDerived04 :: TDerived04 :: TDerived04))를 추가하면 << std :: endl;' GCC, MSVC++, MSVC++에서는 생성자에 대한 인수가 필요하지 않음), 인쇄 된 값은 'true'입니다. 그래서, MSVC++는 당신이 말한 것처럼 그것을 생성자로 취급하려합니다. 그렇다면 왜 GCC가'true'를 인쇄합니까? 그것은 타입'TDerived04'를 다음과 비교합니다 ... 확실하지는 않지만'TDerived04 :: TDerived04 :: TDerived04'를'TDerived04' 타입으로 취급합니다. 아니? – lapk

+0

와우, GCC는'TDerived04 :: TDerived04 :: TDerived04 :: TDerived04 lD4; 변수를 정의 할 수 있습니다. 그리고 타입은 간단히'TDerived04'입니다. 스코프 해상도를 축소하는 규칙이 있습니까? MSVC++는'typeid'에서 같은 일을하는 것처럼 보이지만 다른 시나리오는 처리 할 수 ​​없습니다. – lapk

+0

이것은 TDerived04 클래스에서 TDerived04라는 이름을 사용하여이 클래스/네임 스페이스를 참조 할 수 있다고 설명 할 수 있습니다. 따라서 TDerived04 :: TDerived04는 TDerived04의 TDerived04 클래스를 가리키는 것과 같습니다. 어떤 것이 맞습니까 (비록 그것이 적절한 설명인지는 모르지만). – elmo

관련 문제