Я отказываюсь от этого...
$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