C++14 中泛型 Lambda 中的静态自动变量

Static Auto Variable in Generic Lambda in C++14

class A {
    public:
        int a;
        char b;
        double c;
        A ( int x, char y, double z ) : a(x), b(y), c(z){}
};

int main(){

    auto lambda = []( auto x ) {
        static auto y = x;
        // y = x;
        return y;
    };

    int    a = lambda(1);
    char   b = lambda('a');
    double c = lambda(1.5);
    A      d = lambda( A( 2, 'b', 2.5 ) );

    return 0;
}

此代码在 Clang 3.8.0 和 GCC 5.4.0 中编译,并且运行良好。但是,考虑到变量 ystatic

如果我在每次调用中打印 sizeof(y),我将分别得到 4、1、8 和 16。

On local and global static variables in C++

你的 lambda 是通用的。这意味着这是一个伪装的模板。根据模板特化的一般规则处理这种情况。

对于每个特定的推导类型的参数 x,您将获得函数的单独特化。因此,是的,对于每个特定类型的 x,您都会得到一个单独的 y 副本。但是底层机制并没有以某种方式本地化在您的 static 中,而是您的函数的整个主体 "copied" 产生了该函数的单独独立实现。

你的 lambda 的每个特化都有一个单独的 y 副本,它只会在第一次调用该特定特化时初始化一次。

情况实际上等同于更明确的

template <typename T> void foo(T x)
{
  static T y = x;
  std::cout << y << std::endl;
}

int main()
{
  foo(1);
  foo('a');
  foo(1.5);
  foo(3.0);
}

输出 1a1.51.5

在此示例中,您获得了 foo 的三个独立特化:foo<int>foo<char>foo<double>foo 的每个版本都有自己的 y 版本,这意味着在此示例中有三个不同的静态 y。对每个特化的第一次调用将初始化 y,后续调用将不会重新初始化它。在这种情况下,对 foo(1.5) 的调用会为 foo<double> 初始化 y,但对 foo(3.0) 的后续调用不会。

同样的事情也发生在你的案例中,只是使用了不同的语法。

Lamda with auto 无非是class operator() 重载为模板,使用auto 进行类型推导(遵循模板参数推导规则)

在这种情况下,您拥有与此函数对象模板运算符的实例化一样多的静态 y 字段。

初始化就像手写的那样完成 class 这是第一次触发函数(在这种情况下是 lambda)