lambda 捕获中声明的变量的类型推导

Type deduction for variable declared in lambda's capture

在这段代码中,我在 lambda 的捕获中声明了一个变量 i

int main()
{
    vector<int> vec;

    // Pushing 0-99 numbers to vector
    std::generate_n(std::back_inserter(vec), 100, [i = 0]() mutable { return i++; });

    return 0;
}

如您所见,i.

的任何地方都没有声明类型

据我所知,我可以用这种方式编写等效的功能:

int main()
{
    vector<int> vec;

    // Pushing 0-99 numbers to vector
    std::generate_n(std::back_inserter(vec), 100, [](){
             static int i = 0; 
             return i++; });

    return 0;
}

编译器如何知道第一个例子中i的类型?是从我对其执行的操作推导出来的(++)吗?它知道它是 int 是因为容器吗?

使用带有 -std=c++14 和 -std=c++17 的 GCC 编译时没有任何抱怨。 尽管如此,如果我使用 -std=c++11 编译,我会收到以下警告:

lambda_test.cpp: In function ‘int main()’:
lambda_test.cpp:24:51: warning: lambda capture initializers only available with -std=c++14 or -std=gnu++14
  std::generate_n(std::back_inserter(first), 100, [i = 0]() mutable { return i++; });
                                                   ^

MORE:鉴于评论,我试图查看编译器为 c++11 和 14 生成的内容的差异,但它生成相同的代码: https://cppinsights.io/s/43411e6f

如错误所述,您必须激活 C++14 才能使 lambda 捕获初始化器工作,因为它是在 C++14 中添加的。

As far as I know, I can write the equivalent functionality in this way:

不,静态存储在功能上是不同的。使用捕获,您可以复制 lambda,它将复制捕获的状态。使用静态变量,每个 lambda 访问相同的全局变量。

How does the compiler know the type of i in the first example? Is it deduced from the operation I perform on it (++) ? Does it know that it is int because of the container?

不,因为许多类型都有 ++ 运算符。

编译器简单地使用初始化器来推断类型。你可以看到它好像那里有一个隐藏的 auto:

std::generate_n(std::back_inserter(vec), 100, [/* auto */ i = 0]() mutable { return i++; });

文字 0 的类型为 int。所以 i 是一个 int.

从技术上讲,您也可以这样做:

std::generate_n(std::back_inserter(vec), 100, [/* auto */ i = 0ull]() mutable { return i++; });

然后 i 具有类型 unsigned long long,因为文字 0ull 是该类型。

它就像你做的那样工作

auto i = 0;

如果您不捕获现有变量并且该初始化程序用于确定类型,则必须指定一个初始化程序。