C++ decltype行为背后的基本原理是什么?

C++ decltype行为背后的基本原理是什么?,c++,c++11,c++14,decltype,type-deduction,C++,C++11,C++14,Decltype,Type Deduction,正如我在C++11中所理解的那样,decltype(expression)用于推导与给定表达式完全相同的类型。但当表达式本身放入括号中时,推断类型是对表达式类型的左值引用。例如: int x; decltype(x) y = x; 相当于int y=x但是 int x; decltype((x)) y = x; 相当于int&y=x 分别 decltype(auto) f1() { int x = 0; return x; // decltype(x) is int, so

正如我在C++11中所理解的那样,
decltype(expression)
用于推导与给定表达式完全相同的类型。但当表达式本身放入括号中时,推断类型是对表达式类型的左值引用。例如:

int x;
decltype(x) y = x;
相当于
int y=x但是

int x;
decltype((x)) y = x;
相当于
int&y=x

分别

 decltype(auto) f1()
 {
   int x = 0;
   return x; // decltype(x) is int, so f1 returns int
 }
但是

标准委员会选择这种行为的理由是什么

后记:


现在我观察到,至少在gcc6.2实现的情况下,当括号中的表达式更复杂时,例如
decltype((x+x))
推导的类型是
T
,而不是
T&
。这更令人困惑。我不知道这种行为是否标准。

需要区分实体和表达式

考虑以下问题:

密西西比河有多长

这个问题有两个答案:

  • 密西西比河有2320英里长
  • 密西西比河有11个字母长

  • 同样,当您询问
    x
    的类型,并且
    x
    是一个标识符时,不清楚您指的是用于声明该标识符的类型(即与名称
    x
    关联的类型),还是仅提及该标识符的表达式类型。事实上,可以有两个不同的关键字(例如
    实体类型
    表达式类型
    ),而不是一个重载的
    decltype
    。出于某种原因,委员会选择为这两种不同的用途重载
    decltype

    他们想要一种获得标识符声明类型的方法

    他们还希望找到一种获取表达式类型的方法,包括关于它是否是临时表达式的信息

    decltype(x)
    给出标识符的声明类型
    x
    。如果您传递的
    decltype
    不是标识符,它将确定类型,然后为左值追加
    &
    ,为xvalues追加
    &
    ,为prvalues追加任何内容

    从概念上讲,您可以将其视为变量类型和表达式类型之间的差异。但这并不是标准所描述的


    他们可以用两个不同的关键词来表示这两件事。他们没有。

    来自
    decltype
    提案的作者之一J.Jarvi:

    已经有一段时间了,但我(想我)还记得:

    区分这两种语义的两个单独的关键字 从未考虑过。(引入新关键字并非易事)

    关于
    decltype((x))
    的语义变化,在 核心工作组将
    (x)
    视为一种表达,而不是 而不是标识符,它可能更“内部一致” 遵守语言规则

    人们意识到,在某些情况下,这可能会令人困惑 但共识(也许不是每个人的偏好)是一致的 最终与本标准的先前定义保持一致 什么是标识符,什么是表达式

    你链接到[这个问题的例子]的例子确实令人惊讶。当时,推导出一个 使用
    decltype(auto)
    还不是语言的一部分,所以我不认为这个特殊的用法 任何人都注意到了这个案子


    也许这会很有帮助,他们需要一些方法使decltype能够产生一个ref。所以他们只是滚动随机语法骰子来产生括号。@TartanLlama,
    decltype(auto)
    出现了
    c++14
    ,而
    decltype
    规范是这样的,因为
    c++11
    ,对我来说,这似乎不是原因。老实说,我觉得这是自然的方式
    decltype(identifier)
    是标识符的类型。如果它是一个非ID表达式,则它是T值,如果它是一个LValk,因为C++是这样说的:“指定其他事物的LV值”,显然他们希望人们停止随机地对他们的<代码>返回< /Calp>表达式进行括号化。但是当我给出的不是一个标识符,比如“代码> DECKTYPE(X+1)< <代码>或<代码> DECKTYPE(1)。(x+1))
    在这两种情况下,推导的类型都是
    int
    ,但不是
    int&
    ,也不是更具逻辑性的
    int&
    (使用GCC 6.2和boost::type_索引库进行测试)。为什么?@bobeff因为
    x+1
    是PR值?@bobeff注意
    decltype(x+1)
    将始终与
    decltype((x+1))相同
    无论
    x
    的类型是什么,以及
    操作符+
    如何重载。原因是
    x+1
    是一个表达式,因此在其周围添加括号不会改变任何东西。@Columbo。可能是。From:prvalue不能是多态的:它标识的对象的动态类型始终是ty表达式的pe。
    decltype
    不一定给出对象的动态类型,即使您说
    decltype(x)
    。由
    x
    引用的对象的实际类型(当
    x
    foo.bar
    时)在编译时可能未知。在这种情况下,
    decltype
    应该生成
    x
    引用的成员的声明类型(换句话说,当我们在实体类型“class member”和“object”之间进行选择时,我们必须选择“class member”).这在规范中有点含糊不清,消歧依赖于语言和常识方面的先验知识/专业知识。
     decltype(auto) f2()
     {
       int x = 0;
       return (x); // decltype((x)) is int&, so f2 returns int&
     }