在泛型lambda表达式的所有实例化之间共享的局部静态变量

Local static variable shared between all instantiations of a generic lambda expression

本文关键字:共享 之间 局部 变量 静态 实例化 泛型 lambda 表达式      更新时间:2023-10-16

我有一些代码,其中非泛型lamba表达式有一个局部静态变量:一个关键部分的互斥。可以简化为:

int i = 0;
auto lambda = [&i](int &v)
{
    static std::mutex mutex;
    std::lock_guard<std::mutex> lock(mutex);
    /* critical section with v and i */};
}

现在,这个lambda表达式中实现的关键部分可以逐字逐句地重复用于int &以外的其他类型,我希望有一个简单的更改,比如在声明符中将int替换为auto,如下所示:

auto lambda = [&i](auto &v)

不幸的是,如果我这样做,lambda(int&)lambda(float&)将不再共享同一个局部静态变量,这将破坏关键部分的锁定。

满足所有这些要求的代码中最简单的更改是什么:

  • 提供我需要的通用性;以及
  • 确保在关键部分的所有实例化中共享一个互斥对象;以及
  • 不将互斥对象公开到公共视图

一个可行的解决方案是用一个带有模板方法的类替换lambda表达式,类似于以下内容:

class Lambda
{
public:
    Lambda(int &i) : i_(i) {}
    template<class V>
    void operator()(V &v)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        /* critical section with v and i_ */
    };
private:
    static std::mutex mutex_;
    int &i_;
};
std::mutex Lambda::mutex_;
int i = 0;
Lambda lambda(i);

这是可行的(需要像私有引用i_这样的注意事项),但与初始lambda表达式相比,它看起来非常麻烦。还有什么更直白的吗?

您可以初始化捕获一个shared_ptr,这将类似于将其定义为闭包类型的成员变量,因此闭包对象的所有副本都将共享相同的互斥对象:

  auto lambda = [&i, m = std::make_shared<std::mutex>()](auto &v)
  {
      std::lock_guard<std::mutex> lock(*m);
      /* critical section with v and i */
  };