[英]What is the type of `a ? b : c`?
让我们说我们有
template <typename T>
struct Foo
{};
和
struct Bar
{
template <typename T>
operator Foo<T>() const { return Foo<T>(); }
};
和
template <typename T>
Foo<T> Baz(T const&) { return Foo<T>(); }
那么, true ? Bar() : Baz(some_expr_of_type_double)
true ? Bar() : Baz(some_expr_of_type_double)
类型为Foo<double>
因为Bar
可以转换为Foo<double>
。 此技巧用于在不some_expr_of_type_double
进行评估的some_expr_of_type_double
下查询some_expr_of_type_double
的类型。
确定a ? b : c
类型的规则a ? b : c
a ? b : c
? 我很欣赏标准的相关部分(我没有副本)。 有没有“ typeof(b)
必须可以转换为typeof(c)
,反之亦然,毫无疑问”?
这是相关规范:
条件表达式从右到左分组。 第一个表达式隐式转换为bool(第4节)。 它被评估,如果是,则条件表达式的结果是第二个表达式的值,否则是第三个表达式的值。 除了临时破坏(12.2)之外,第一个表达式的所有副作用都发生在评估第二个或第三个表达之前。 仅评估第二和第三表达式中的一个。
如果第二个或第三个操作数具有类型(可能是cv-qualified)void,则左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换是在第二和第三个操作数上执行,并且以下之一应该成立:
- 第二个或第三个操作数(但不是两个)是一个throw-expression(15.1); 结果是另一个的类型,是一个右值。
- 第二个和第三个操作数都有类型void; 结果是void类型,是一个rvalue。
[注意:这包括两个操作数都是throw-expressions的情况。 ]
否则,如果第二个和第三个操作数具有不同的类型,并且具有(可能是cv-qualified)类类型,则尝试将每个操作数转换为另一个操作数的类型。 确定T1类型的操作数表达式E1是否可以转换为匹配类型T2的操作数表达式E2的过程定义如下:
3.a:如果E2是左值:如果E1可以被隐式转换(第4节)到类型“引用到T2”,则E1可以被转换为匹配E2,受制于转换中引用必须直接绑定的约束( 8.5.3)到E1。
3.b:如果E2是右值,或者上述转换不能完成:
3.b.1:如果E1和E2具有类类型,并且底层类类型相同或者一个是另一个类的基类:如果T2的类与类型相同,则E1可以转换为匹配E2,或T1的基类,T2的cv资格和与T1的cv资格相同的cv资格或更高的资格。 如果应用转换,则将E1更改为类型T2的右值,该值仍然引用原始源类对象(或其相应的子对象)。 (注意:即没有复制。)
3.b.2:否则(即,如果E1或E2具有非类型类型,或者它们都具有类类型但基础类不是相同的或一个是另一个的基类):E1可以转换为如果E2可以隐式转换为表达式E2,如果E2被转换为rvalue(或者它具有的类型,如果E2是rvalue),则匹配E2。
使用该过程,确定是否可以转换第二操作数以匹配第三操作数,以及是否可以转换第三操作数以匹配第二操作数。 如果两者都可以转换,或者一个可以转换,但转换不明确,则程序格式不正确。 如果两者都不能被转换,则操作数保持不变并且如下所述执行进一步检查。 如果只能进行一次转换,则将该转换应用于所选操作数,并使用转换后的操作数代替本节其余部分的原始操作数。
如果第二个和第三个操作数是左值并且具有相同的类型,则结果是该类型并且是左值。
否则,结果是右值。 如果第二个和第三个操作数不具有相同的类型,并且具有(可能是cv限定的)类类型,则使用重载决策来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6) 。 如果重载决策失败,则程序格式错误。 否则,应用如此确定的转换,并使用转换的操作数代替本节其余部分的原始操作数。
在第二个和第三个操作数上执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换。 完成转换后,以下其中一项应成立:
6.a:第二个和第三个操作数具有相同的类型; 结果是那种类型。
6.b:第二个和第三个操作数具有算术或枚举类型; 执行通常的算术转换以使它们成为公共类型,结果是该类型。
6.c:第二个和第三个操作数具有指针类型,或者一个具有指针类型,另一个是空指针常量; 执行指针转换(4.10)和限定转换(4.4)以将它们带到它们的复合指针类型(5.9)。 结果是复合指针类型。
6.d:第二个和第三个操作数具有指向成员类型的指针,或者一个指向成员类型的指针,另一个是空指针常量; 执行指向成员转换(4.11)和限定转换(4.4)的指针,以使它们成为一个公共类型,其cv资格应匹配第二个或第三个操作数的cvqualification。 结果是普通类型。
它不仅仅是(b)类型必须可转换为(c)类型。 这是一套复杂的规则,在5.16:2-6中列出; 关于一页长度。 有一些尝试和一堆关于左值与右值的东西。
标准(您可以在这里找到的当前草案)在解释确切的打字程序时做了彻底的,如果不一定清楚的工作。 我得到的是表达式(BOOL?Y:Z):
它首先检查从Y到Z的隐式或显式转换类型。然后检查类似的基类,或者是否可以将Y类转换为Z.
当然,这个标准是难以消化的,我可能会非常偏离这里,但从我所读到的,突出的部分是我们总是尝试Y-> Z转换。 这将使我们相信结果也是Z型。这有趣的副作用是,如果我们放置X =(BOOL?Y:Z)并且存在Y-> X和Z-> X转换,但没有Y-> Z转换,那么程序就不正确了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.