Указатели каста и тройной?: Оператор. Разве я изобрел колесо?

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

У действительно умного компилятора не должно быть никаких трудностей, потому что оба могут быть безопасно добавлены к B* (базовому классу). Я не хочу использовать static_cast и dynamic_cast и так далее. Я беспокоюсь, что когда-нибудь буду смешивать классы и получать поведение undefined. Вот почему я создал шаблон 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 в соответствии с ответом @Konrad

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Эта же операция выполняется с охватывающим выражением, где теперь второй аргумент &d1 (type D1*), а тип третьего аргумента - B*. Опять же, преобразование тривиально с повышением уровня D1*, а тип всего выражения B*.

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

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

Ответ 3

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

b = boolean_expression ? new D1 : new D2;

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

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

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

Ответ 4

Я только сталкивался с этой проблемой, теряю броски и делаю это - самый чистый ИМО

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