【问题标题】:Static Auto Variable in Generic Lambda in C++14C++14 通用 Lambda 中的静态自动变量
【发布时间】:2017-02-22 16:08: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

  • 变量y的类型是什么? y 的类型是否会在每次调用 lambda 时发生变化?
  • 变量y 是否在每次调用中初始化,尽管是static?不需要注释赋值// y = x 来更新变量y 的值。
  • 这种行为是否符合 C++14 标准?

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

On local and global static variables in C++

【问题讨论】:

  • 通用 lambda 的operator (...) 或多或少是一个函数模板。因此,将为函数的每个单独实例创建静态变量。

标签: c++ lambda static c++14 auto


【解决方案1】:

您的 lambda 是 通用的。这意味着这是一个变相的模板。这种情况按照模板特化的一般规则处理。

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

每个 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&lt;int&gt;foo&lt;char&gt;foo&lt;double&gt;foo 的每个版本都有自己的y 版本,这意味着在此示例中存在三个不同的静态ys。对每个特化的第一次调用将初始化y,随后的调用将不会重新初始化它。在这种情况下,对foo(1.5) 的调用会为foo&lt;double&gt; 初始化y,但随后对foo(3.0) 的调用不会。

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

【讨论】:

  • 太棒了!这很有意义。我还打印了变量 y 的地址,实际上它与不同类型的 lambda 调用不同,并且对于具有相同类型参数的调用来说,它是相同的地址。我知道static 变量和模板,但我并不完全理解这种行为。现在我知道了,非常感谢!
【解决方案2】:

Lamda with auto 只不过是一个类,将 operator() 重载为模板并使用 auto 进行类型推导(遵循模板参数推导的规则)。

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

初始化就像手写类一样,这是第一次触发函数(在这种情况下是 lambda)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2014-05-12
    • 2017-03-09
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    相关资源
    最近更新 更多