代码之家  ›  专栏  ›  技术社区  ›  Alexandre C.

a的类型是什么?b:c`?

c++
  •  6
  • Alexandre C.  · 技术社区  · 14 年前

    假设我们有

    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) 具有类型 Foo<double> 因为 Bar 可转换为 Foo<双> . 此技巧用于查询 some_expr_of_type_double 而不是评估它。

    确定类型的规则是什么 a ? b : c ? 我很感激标准的相关部分(我没有副本)。是否有超过“ typeof(b) 必须可转换为 typeof(c) 或者反之亦然,毫不含糊地“?

    4 回复  |  直到 14 年前
        1
  •  4
  •   John Dibling    14 年前

    以下是相关规范:

    5.16条件运算符

    1. “条件表达式”组 从右向左。第一个表达式 隐式转换为bool (第4条)。它被评估,如果 是真的,结果是 条件表达式是 第二个表达式,否则 第三种表达方式。全部 第一个表达式的副作用 除了破坏 临时(12.2)发生在 第二个或第三个表达式是 评价的。只有一秒钟 计算第三个表达式。

    2. 如果第二个或第三个操作数的类型(可能是cv限定的)为void,则在第二个和第三个操作数上执行左值到rvalue(4.1)、数组到指针(4.2)和函数到指针(4.3)的标准转换,并应保持以下之一:

      第二个或第三个操作数(但不是两者)是一个抛出表达式(15.1);结果是另一个操作数的类型,并且是一个右值。

      第二个和第三个操作数都有void类型;结果是void类型,并且是一个右值。

      [注意:这包括两个操作数都是抛出表达式的情况。]

    3. 否则,如果第二个和第三个操作数具有不同的类型,并且其中一个具有(可能是cv限定的)类类型,则会尝试将这些操作数中的每一个转换为另一个操作数的类型。确定T1类型的操作数表达式E1是否可以转换为与T2类型的操作数表达式E2匹配的过程定义如下:

      3.a:如果E2是左值:如果E1可以隐式转换(第4条)到对T2的类型引用,则可以将E1转换为与E2匹配,但受转换中引用必须直接绑定(8.5.3)到E1的约束。

      3.b:如果E2是rvalue,或者无法进行上述转换:

      3.b.1:如果E1和E2具有类类型,并且基础类类型相同或一个是另一个的基类:如果T2的类与T1的类相同或是T1的基类,并且T2的cv限定与T1的cv限定相同,或cv限定大于,T1的cv资格。如果应用了转换,则E1将更改为T2类型的rvalue,该rvalue仍然引用原始源类对象(或其相应的子对象)。(注:即不复制。)

      3.b.2:否则(即,如果E1或E2具有非类类型,或者它们都具有类类型,但基础类不是相同的,或者其中一个是另一个的基类):如果E1可以隐式转换为表达式E2转换为rvalue(或者如果E2是价值观)。

      使用此过程,将确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者一个可以转换但转换不明确,则程序格式错误。如果两者都不能转换,则操作数保持不变,并按如下所述执行进一步检查。如果只有一个转换是可能的,则该转换将应用于所选操作数,并在本节剩余部分使用转换后的操作数代替原始操作数。

    4. 如果第二个和第三个操作数是左值,并且具有相同的类型,则结果属于该类型,并且是左值。

    5. 否则,结果为rvalue。如果第二个和第三个操作数不具有相同的类型,并且其中一个具有(可能是cv限定的)类类型,则使用重载解析来确定要应用于操作数(13.3.1.2、13.6)的转换(如果有)。如果重载解析失败,则程序格式错误。否则,将应用由此确定的转换,并在本节剩余部分使用转换后的操作数代替原始操作数。

    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限定应与第二个或第三个操作数的cv限定相匹配。结果是普通类型的。

        2
  •  3
  •   Edward Strange    14 年前

    它多于typeof(b)必须可转换为typeof(c)。这是5.16:2-6中列出的一组复杂的规则;大约一页长。关于左值和右值,有一系列的尝试。

        3
  •  0
  •   fredoverflow    14 年前

    你有一个C++ 0x编译器吗?那样的话 decltype(a ? b : c) 也许 吧?但不确定这个句柄是否正确引用。有人吗?

    我很感激标准的相关部分(我没有副本)

    你可以得到 current draft 免费的 WG21 website .

        4
  •  0
  •   rtpg    14 年前

    标准(您可以找到的当前草稿 here )做一个彻底的,如果不一定清楚的工作,解释确切的打字程序。我从中得到的是 为了表达(布尔?Y: Z):

    它首先检查从Y到Z的隐式或显式转换类型。 然后它检查是否有相似的基类,或者Y是否可以被分类为Z。

    当然,标准是相当难以消化的,我在这里可能会非常离谱,但从我所读到的内容来看,最突出的部分是,我们总是在尝试Y->Z转换。这会让我们相信结果也是Z型的,一个有趣的副作用是如果我们把X=(BOOL?Y:Z)并且存在y和gt;x和z和gt;x转换,但没有y和gt;z转换,则程序将是不正确的。