铸造指针和三元?:操作人员我重新发明轮子了吗

Casting pointers and the ternary ?: operator. Have I reinvented the wheel?

本文关键字:新发明 操作 指针 三元      更新时间:2023-10-16

此代码的最后一行无法使用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

更新根据@Konrad的回答

将名称从implicit_cast更改为up_cast

一个真正聪明的编译器不会有任何困难,因为两者都可以安全地广播到B*

无关。标准要求这种行为。一个真正聪明的编译器的行为正如所观察到的那样。

使用自定义强制转换实际上很好(而且您不愿意使用显式强制转换的情况也很好)。然而,我会使用一个不同的名称:upcast——因为这是在这里发生的:在继承层次结构中向上转换。

[三元]条件运算符要求其第二个和第三个操作数具有相同的类型。

b = boolean_expression ? new D1 : new D2;

您有不同的类型D1*D2*。正如错误消息所示,您必须通过显式转换(即强制转换)确保正确的类型:

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

标准规定编译器必须这样做(而不仅仅是进行隐式转换),所以这就是编译器的要求。

我本来不打算回答,但在发布评论后,我想,这是什么。。。这是一种与其他方法一样的方法:

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(类型为D1*),第三个参数的类型是B*。同样,通过向上投射D1*,转换是微不足道的,并且整个表达式的类型是B*

由于所有的转换都是由编译器隐式执行的,如果您更改指针的类型,并打破它们可以隐式转换的不变,编译器会告诉您,解决了在三元运算符中间抛出static_cast的问题。

1标准规定了一组不同的转换,具体取决于参数的类型。在两个参数是指针的特殊情况下(如这里的情况),允许的转换是指针转换限定转换

我刚刚遇到了这个问题,丢失了铸造,用的方法进行铸造是最干净的IMO

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