Динамическая путаница

Я отказываюсь от этого...

$5.2.7/2- "Если T - тип указателя, v должно быть rзначением указателя на полный тип класса, и результат r значение типа T. Если T является ссылочный тип, v должен быть lvalue полного типа класса, и результатом является lзначение типа обозначаемый Т.

В соответствии с вышесказанным, следующий код должен быть хорошо сформирован.

struct A{};
struct B : A{};

int main(){
   B b;
   A a, &ar1 = b;

   B& rb1 = dynamic_cast<B&>(ar1);  // Does not $5.2.7/2 apply here?
   B& rb2 = dynamic_cast<B&>(a);    // and also here?
}

Но это не так. Все компиляторы жалуются на то, что операнд для dynamic_cast не является полиморфным в соответствии с

$5.2.7/6- В противном случае v будет указатель на или значение l полиморфный тип (10.3).

Итак, мой вопрос в том, что означает $5.2.7/2? Почему здесь стоит $5.2.7/6?

Ответ 1

"В противном случае" в этом случае означает "если не применяются условия в 5.2.7/5".

Вы можете сказать это, потому что /2 устанавливает требование к программе относительно операнда dynamic_cast (обратите внимание, что язык "должен" "v должен быть lvalue" по сравнению с "is" языком "результатом является lvalue" ). Как и в других местах в стандарте, выражение требования не обязательно означает, что это единственное требование. В других положениях могут указываться дополнительные требования. В этом случае /6 указывает дополнительное требование, которое применяется только в определенных случаях, в зависимости от T и статического типа v.

/3,/4,/5 сообщают вам о значении результата, и они полностью согласуются с требованием в /2. Ни один из них не начинается с "Иначе". Поэтому для меня довольно очевидно, что они не образуют цепочку "else if", начинающуюся с /2.

Некоторые скобки или что-то могут сделать это более ясным (то есть, что "в противном случае" в /6 относится к "if" в /5, а не к "if" в /2,/3 или/4). Но это просто не стиль дома.

Помимо всего прочего, "в противном случае" в /5 логически не может осмысленно применяться к условиям в /2./1 говорит, что T должен быть "указателем или ссылкой на полный тип класса, или cv void*". /2 охватывает два случая - типы указателей и ссылочные типы. Это все. Нет "в противном случае" для /2 (если не сказать "иначе, соответствующий компилятор должен выдать диагностику", но это неявно)

Ответ 2

Ну, все требования в 5.2.7 должны соблюдаться вместе. Вы не можете просто остановиться после 5.2.7/2 и начать писать код, который предположительно удовлетворяет всем "до 5.2.7/2". Все 5.2.7 определяют спецификацию dynamic_cast.

Полиморфное требование выделяется, поскольку оно является условным. Когда вы используете dynamic_cast для upcasts, полиморфное требование не применяется (фактически, dynamic_cast эквивалентно static_cast в upcasts). Полиморфное требование применяется только тогда, когда вы используете dynamic_cast для downcasts или crosscasts.

Спецификация dynamic_cast организована последовательно, а это означает, что сначала она заботится о более простых случаях, а затем переходит к более сложным приложениям. Вы должны читать его шаг за шагом, пока он не покрывает вашу конкретную ситуацию. Все, что вы читаете по этому пути, применяется кумулятивно. И "в противном случае" означает: "если мы еще не рассмотрели ваше дело, продолжайте читать".

Ответ 3

Чтобы сделать downcast, как в вашем примере, Struct A должен быть полиморфным и иметь RTTI. Здесь скорректированная версия, которая работает, до точки:

struct A{virtual void f(){}};
struct B : A{};

int main(){
   B b;
   A a, &ar1 = b;

   B& rb1 = dynamic_cast<B&>(ar1);  // Does not $5.2.7/2 apply here?
   //B& rb2 = dynamic_cast<B&>(a);    // and also here?
}

Добавив виртуальное, делая его полиморфным, RTTI включен для класса, позволяя downcasts.

Обратите внимание, что ваш второй пример не может работать - поскольку вы накладываете pod (a) на ссылку на pod - это недопустимо.


Update:

Ваш код не разрешен в соответствии с 5.2.7.5 и не разрешен в соответствии с 5.2.7.6. Моя настройка позволяет работать в соответствии с 5.2.7.6