愚蠢的条件表达式
首先看一段代码:
1: class B {};
2: class D1 : public B {};
3: class D2 : public B {};
4: void main()
5:
{
6:
D1* pD1;
7:
D2* pD2;
8:
B* pB = true ? pD1 : pD2;
9:
}
上面代码第八行能通过编译吗?根据直观理解,它“等价”于
1: if (true)
2:
pB = pD1;
3: else
4:
pB = pD2;
如果编译不过,这种编译器绝不能要。可编译结果还真的是*失败*。第一次与这种问题亲密接触时,你会不会先骂一句‘愚蠢的条件表达式’呢!
条件表达式类型
骂舒坦之后,顺便找找茬,分析一下编译失败原因。表达式都有类型,遇到不能确定类型的表达式,编译就会失败。条件表达式是表达式(废话)。确定条件表达式类型的规则冗长且复杂,C++标准有一整页来描述。但是对非内置类型,其核心规则比较简单。设 X
和 Y
为第二个和第三个操作数所属的类型,
- 如果
X
和Y
的类型相同,则此类型为该条件表达式的类型。 - 否则,如果存在从
X
到Y
的隐式转换,但不存在从Y
到X
的隐式转换,则Y
为条件表达式的类型。 - 否则,如果存在从
Y
到X
的隐式转换,但不存在从X
到Y
的隐式转换,则X
为条件表达式的类型。 - 否则,无法确定条件表达式的类型,且发生编译时错误。
根据上述规则,true? pD1 : pD2 的类型是无法确定的,所以编译时错误在所难免。
为什么要编译时确定表达式类型
既然是找茬,那就打破沙锅问到底。我知识浅薄,无法彻底弄明白。只是找到一些蛛丝马迹。
- C++是强类型静态语言,编译期确定表达式类型有助于编写类型安全代码。
- 泛型编程早已深入人心,而泛型编程中常常需要知道表达式的类型。C++0x甚至专门引入了decltype关键字来取得表达式的类型。
为什么不对赋值运算做特殊处理
第八行代码这种情况,为什么不对条件表达式类型做特殊处理,使得上述“等价”真的等价。似乎挺合理。嗯,那是你认为。特痛恨PD弄那么多特殊情况,把设计弄得乱七八糟,把Dev搞得死去活来。尽管这些特例看上去有一定道理,如本例。