为什么可以(false?A():B()).test()仅在A和B具有子类关系时编译?

ggr*_*grr 21 c++ syntax inheritance ternary-operator

本来我喜欢用这样的东西:

(true?a:b).test()
Run Code Online (Sandbox Code Playgroud)

代替

(true?a.test():b.test())
Run Code Online (Sandbox Code Playgroud)

如果函数具有相同的名称,为了节省打字时间,最初我认为它应该是有效的,但我发现:

#include <stdio.h>
class A{
public:
    char test(){
        return 'A';
    }
};

class B{
public:
    char test(){
        return 'B';
    }
};

int main(){
    printf("%c\n",(false?A():B()).test());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

无法编译,但如果B是子类A:

#include <stdio.h>
class A{
public:
    char test(){
        return 'A';
    }
};

class B : public A{
public:
    char test(){
        return 'B';
    }
};

int main(){
    printf("%c\n",(false?A():B()).test());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它可以编译,为什么?

MSa*_*ers 52

原因是它(test?a:b)是一个表达式,必须有一个类型.该类型是a和b的常见类型,不相关的类型没有共同的类型.基类和派生类的通用类型是基类.

请注意,该问题包含一个假设,即编译的唯一情况是存在共同基类型的情况.实际上,如果从一种类型到另一种类型的明确转换,它也会编译.


Nia*_*all 18

条件运算符(?:)操作数必须具有公共类型.即E1 ? E2 : E3当时给出E2,E3必须明确无误.然后,此类型是返回类型,然后将其用作表达式的整体.

cppreference,他们列出了规则和要求,但这里的相关重点是;

条件运算符的返回类型也可以作为二进制类型特征访问 std::common_type

这基本上是说必须有一个共同的类型,std::common_type并可用于计算该类型.

基于您的代码片段(true ? a.test() : b.test()),两者都有效a.test()b.test()返回char.但是a并且b无关,因此不能单独使用.


发现C++(WD n4527)标准中的相关材料是§5.16([expr.cond]).应用了几个规则和转换,其要点是如果没有转换,或者转换不明确,程序就会格式不正确.