Кастинг указателей и троичный?: Оператор. Я заново изобрел колесо? - PullRequest
10 голосов
/ 30 мая 2011

Последняя строка этого кода не компилируется с castingAndTernary.cpp:15: error: conditional expression between distinct pointer types ‘D1*’ and ‘D2*’ lacks a cast

По-настоящему умный компилятор может не испытывать затруднений, потому что оба можно безопасно привести к B* (базовый класс). Я не хочу использовать static_cast, dynamic_cast и т. Д., Я боюсь, что когда-нибудь перепутаю классы и получу неопределенное поведение. Вот почему я создал шаблон up_cast. Этот шаблон делает минимум в разрешенной конверсии. Есть ли более простой способ? Есть и другие обходные пути, но я не могу не думать, что есть что-то еще более простое и безопасное, что я мог бы использовать?

struct B{ };
struct D1 : public B{ };
struct D2 : public B{ };

template<typename T,typename V>
T up_cast(V x) {
        return x;
}
int main() {
        bool boolean_expression = true;
        B * b;
        b = new D1;
        b = new D2;
        b = boolean_expression ? up_cast<B*>(new D1) : up_cast<B*>(new D2);
        b = boolean_expression ? new D1 : new D2;
}

g ++ (Ubuntu 4.3.3-5ubuntu4) 4.3.3

Обновление изменено имя с implicit_cast на up_cast согласно ответу @ Конрада

Ответы [ 4 ]

8 голосов
/ 30 мая 2011

По-настоящему умный компилятор может не испытывать затруднений, потому что оба можно безопасно привести к B*

Неактуально.Стандарт предписывает такое поведение.По-настоящему умный компилятор ведет себя так, как он наблюдал.

Использование вашего каста на самом деле хорошо (и ваше нежелание использовать явный кастинг вполне приемлемо).Однако я бы использовал другое имя: upcast - поскольку это происходит здесь: приведение вверх в иерархии наследования.

6 голосов
/ 30 мая 2011

Я не собирался отвечать, но после публикации комментария я подумал, что ... это подход, как и любой другой:

int main() {
   bool condition = true;
   D1 d1;
   D2 d2;
   B * p = condition ? &d1 : (true? &d2 : p );
}

В основном злоупотребляют троичным оператором для извлечения соответствующего типа,Когда компилятор обрабатывает троичный оператор, он пытается определить, можно ли неявно преобразовать два операнда в общий тип 1 , и если это так, он использует этот общий тип в качестве типавыражение.

В приведенном выше коде внутренний троичный оператор: true? &d2 : p попытается сопоставить тип выражения &d2 с типом p, он обнаружит, что существует простойupcast, что он может выполнить и установит тип возврата для этого подвыражения равным B*.Обратите внимание, что, поскольку условие true, оно всегда будет выдавать &d2, даже если для определения типа используется третий аргумент.

Та же операция выполняется с включающим выражением, где теперь второеаргумент &d1 (тип D1*) и тип третьего аргумента B*.Опять же, преобразование тривиально, выгрузив D1*, и тип всего выражения: B*.

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

1 Стандартдиктует набор различных преобразований, в зависимости от типов аргументов.В частном случае, когда два аргумента являются указателями (как в данном случае), допустимыми являются преобразования преобразования указателей и преобразования квалификации .

4 голосов
/ 30 мая 2011

Условный оператор [ternary] требует, чтобы его второй и третий операнды имели одинаковый тип.

b = boolean_expression ? new D1 : new D2;

У вас есть различные типы D1* и D2*. Как указывает сообщение об ошибке, вы должны обеспечить правильный тип с явным преобразованием (то есть приведением):

b = boolean_expression ? static_cast<B*>(new D1) : static_cast<B*>(new D2);

Стандарт гласит, что компиляторы должны требовать этого (вместо того, чтобы просто выполнять неявное преобразование), так что это то, что требует ваш компилятор.

0 голосов
/ 21 января 2019

Я только что столкнулся с этой проблемой, проиграл броски и сделал это, long - самый чистый IMO

B * d1 = new D1();
B * d2 = new D2();
B * b = boolean_expression ? d1 : d2;
...