c++ - decltype行为背后的理由是什么?



c++11 c++14 type-deduction (4)

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

已经有一段时间了,但这就是我(想想我)记得的:

从未考虑过用于区分这两种语义的两个单独的关键字。 (引入新关键字不是轻易做到的)。

至于decltype((x))语义的变化,核心工作组的讨论收敛于将(x)视为表达式而不是标识符,它可能与语言规则更“内部一致”。

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

你链接到[这个问题的例子]的例子确实令人惊讶。 当时,使用decltype(auto)从返回表达式中推导函数的返回类型还不是语言的一部分,所以我不认为这个特定的用例是在任何人的雷达上。

正如我在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
 }

 decltype(auto) f2()
 {
   int x = 0;
   return (x); // decltype((x)) is int&, so f2 returns int&
 }

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

后记:

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


需要区分实体和表达。

请考虑以下问题:

密西西比河有多长?

这个问题有两个答案:

  1. 密西西比河长2,320英里。
  2. 密西西比州长11个字母。

类似地,当您询问x的类型,并且x是标识符时,不清楚您是否表示用于声明该标识符的类型(即与名称x关联的类型),或者包含的表达式的类型唯一提到的标识符。 事实上,可能有两个不同的关键字(例如entity_typeexpr_type )而不是单个重载的decltype 。 出于某种原因,委员会选择对这两种不同的用途decltype


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

他们还想要一种方法来获取表达式的类型,包括它是否是临时的信息。

decltype(x)给出标识符x的声明类型。 如果你传递的decltype不是一个标识符,它会确定类型,然后为lvalues附加& ,为xvalues附加&&为prvalues添加任何内容。

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

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


lambda函数是您创建的匿名函数。 它可以捕获一些已经解释过的变量(例如http://www.stroustrup.com/C++11FAQ.html#lambda ),但有一些限制。 例如,如果有这样的回调接口,

void apply(void (*f)(int)) {
    f(10);
    f(20);
    f(30);
}

你可以在现场编写一个函数来使用它,就像下面通过的函数一样:

int col=0;
void output() {
    apply([](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

但是你不能这样做:

void output(int n) {
    int col=0;
    apply([&col,n](int data) {
        cout << data << ((++col % 10) ? ' ' : '\n');
    });
}

因为C ++ 11标准的局限性。 如果你想使用捕获,你必须依靠图书馆和

#include <functional> 

(或其他一些类似于算法的STL库来间接获取它),然后使用std :: function而不是像下面这样的参数传递普通函数:

#include <functional>
void apply(std::function<void(int)> f) {
    f(10);
    f(20);
    f(30);
}
void output(int width) {
    int col;
    apply([width,&col](int data) {
        cout << data << ((++col % width) ? ' ' : '\n');
    });
}




c++ c++11 c++14 decltype type-deduction