Как компилятор оценивает оператор `typeid`? - PullRequest
1 голос
/ 03 января 2012

Вот пример кода шаблона на основе CRTP , который я использовал, чтобы попытаться решить этот вопрос: Требование переопределенных виртуальных функций для вызова базовых реализаций . Я бы разместил здесь код, но строки длинные и их легче читать на codepad.org (при необходимости я опубликую здесь). Конечно, это некрасиво и несколько искусственно, хотя и работает. Но то, что я сначала не осознавал, это то, что, хотя он компилируется как в MSVC ++, так и в GCC, некоторые типы шаблонов на самом деле не определены. Часть, о которой я спрашиваю, - это несколько длинных внутренних if( typeid( Derived(N) ) != typeid( Derived(N-1)) (символьных обозначений) в функции TBase::OnEvent сверху.

Вы не можете typdef этих типов, это будет ошибка компиляции - просто недостаточно производных классов для определения типа с такой длинной цепочкой ...::TDerived::..., поэтому вы получите, правильно, ошибку компиляции TDerived is not defined in TBase. И все же компилятор ест их через typeid. Когда я проверял выходные данные компилятора отладчика MSVC ++ (с полной символической информацией), кажется, что все эти длинные ...::TDerived::..., которые не должны действительно приводить ни к какому классу, в typeid разрешаются компилятором просто в последний TDerived04 в цепочке классов , И RTTI тянется для этого последнего класса в цепочке классов, независимо от того, сколько ...::TDerived::... у меня есть.

Учитывая, что MSVC ++ и GCC делают это (хотя у меня есть доступ к GCC только через codepad.org), мой вопрос следующий: это как-то определяет поведение typeid? Почему тогда typedef любого из этих длинных ...::TDerived::... не разрешается до TDerived04?

РЕДАКТИРОВАТЬ: я имею в виду, я счастлив typedef не разрешается до TDerived04, это будет катастрофой для всех, кто использует typedef, но почему такая несоответствие между typeid и typedef?

РЕДАКТИРОВАТЬ: GCC принимает объявление переменной TDerived04::TDerived04::TDerived04::TDerived04 lD4;. И тип просто TDerived04 в конце. Есть ли правило для свертывания разрешения области? Очевидно, что и MSVC ++, и GCC, похоже, делают то же самое в typeid, но MSVC ++, в отличие от GCC, не может обрабатывать другие сценарии - он выдает ошибку компиляции, требуя аргументов для конструктора (ов).

Ответы [ 2 ]

1 голос
/ 04 января 2012

Я бы не стал использовать typeid как инструмент для отладки. Стандарт C ++ только гарантирует его существование, но на самом деле не говорит, что он должен делать. Это делает эту уместность не более чем способом печати имен классов, удобочитаемых человеком (исправьте меня, если вы знаете какое-либо другое практическое использование).

Я бы сказал, что слишком большое «определенное компилятором» поведение typeid, чтобы сделать его полезным для чего-то еще, чем выше.

Подход, представленный в решении, также имеет огромный недостаток. Помимо того, что базовый класс уродлив и сложен в обслуживании, он должен знать обо всех производных классах. Это довольно большой недостаток дизайна.

Что касается альтернативного решения, его можно увидеть здесь (код также размещен в оригинальном вопросе).

Что касается действительности TDerived04::TDerived04::TDerived04::TDerived04, то это можно объяснить тем, что в классе TDerived04 вы можете обращаться к этому классу / пространству имен, используя его имя TDerived04. Так что TDerived04 :: TDerived04 похоже на указание на класс TDerived04 из TDerived04 (как сказал @MSalters, это называется «внедрение имени класса»).

1 голос
/ 03 января 2012

Проблема примерно в том, что между введенным именем класса и именем конструктора существует неоднозначность. В области действия class X, X может называть сам класс, но X::X может также ссылаться на конструктор - , где это имеет смысл .

...