Ответ 1
Если бы я уделял больше внимания самому следующему пункту (5.2.8/3), я бы увидел это
Когда typeid применяется к выражение, отличное от значения l тип полиморфного класса., Выражение не оценивается.
Другими словами, как и в случае с sizeof
(в частности, в С++ 11), компилятор не предназначен для фактического запуска кода, который вы передаете в typeid
, он просто должен анализировать его для поведения. К сожалению, в отличие от sizeof
, результат иногда зависит от поведения во время выполнения выражения из-за полиморфных типов.
Base* p1 = new Derived;
Base* p2 = new Base;
typeid(*p1); //equivalent to typeid(Derived) [assuming Base is polymorphic]
typeid(*p2); //equivalent to typeid(Base)
Если выражение было полностью не оценено, компилятор не смог проверить RTTI, чтобы увидеть, что p1
фактически указывает на Derived
вместо Base
. Однако стандартные авторы решили сделать еще один шаг и заявили, что если выражение в конечном счете является разыменованием типа указателя, компилятор должен его только частично оценить. Если указатель имеет значение null, бросьте std::bad_typeid
вместо выполнения разыменования и введя поведение undefined.
Сравните это с dynamic_cast
. Выражение, переданное в dynamic_cast
, всегда полностью оценивается, результат не имеет смысла. Поскольку компилятор должен полностью оценить выражение во всяком случае, нет смысла указывать ему, чтобы он остановился раньше и выбрал исключение.
Короче говоря, этому уделяется особое лечение во многом так же, как при специальном лечении sizeof(*(int*)0)
. *(int*)0
не предназначен для оценки, поэтому нет причин вводить поведение undefined в первую очередь, хотя оно выглядит плохо.