使用模板参数推导将lambda存储为成员

Store lambda as a member using template arguments deduction

本文关键字:lambda 存储 成员 参数      更新时间:2023-10-16

以前,当 c++ 11可用时,我尝试使用auto说明符和成员初始化式将lambda存储为类字段。这是一次不成功的尝试:

struct Y
{
    auto x = [] { ; };
};
错误:

错误:用占位符'auto'声明非静态数据成员

尽管在定义类成员时已知lambda的大小(w/o丧失了捕获的通用性),但不允许使用auto指示符。为什么?限制不太明确

现在可以在GCC 7.0.0 trunk中使用类模板的模板参数推导。我试着再做一次:

template< typename F >
struct X
    : F
{
    using F::operator ();
    X(F && f) : F(static_cast< F && >(f)) { ; }
};
struct Y
{
    X x = [] { ; };
};

但是我得到一个错误:

错误:无效使用模板名'X'没有参数列表

我怀疑,实现是部分的,甚至可能不一致。它是否允许我实现所需的w/o类型擦除(和内存的动态分配)?

允许自由的非成员定义:

X x = [] { ; };

附加:

人们问我试图解决什么问题?对于类内定义的函子,我需要一个简洁的语法。

如果我能写(下面的代码是有效的):

struct point_of_parabaloid // aggregate
{
    double x, y;
    double z = [&] { return x * x + y * y; }();
};
point_of_parabaloid p = {1.0, 2.0};
assert(p.z == 5.0);

为什么我不能定义一个类内lambda(说,为z的惰性评估)?

我不需要捕获异常的东西,只是一个类成员(或this)在point_of_parabaloid定义

如果lambda事先已知,则可以使用decltype解决此问题:

auto lambda = [](){};
struct C {
  decltype(lambda) member = lambda;
};

不是很漂亮,但是很好用。

我认为你的模板技术可以工作,如果重写为:

auto x = X([](){});

但是gcc-7 (snapshot)也不接受。我怀疑这是因为它仍在进行中。

[刚刚在20161014上构建的g++ 7主干上再次测试,然后上述工作]

你可以使用maker函数

来解决这个问题
template <typename L>
struct X {
  L member;
};
template <typename T>
auto make_x(T t) { return X<T>{t}; }
auto x = make_x([](){});

您的问题是您试图在类定义中捕获成员函数之外的this。确切地说,double z = [&] { return x * x + y * y; }();需要this->xthis->y

你现在进入了一个循环依赖:lambda的类型取决于捕获的内容(this,这是point_of_parabaloid*),但point_of_parabaloid取决于其成员的类型,包括那个lambda。

在你的设计中这是一个循环依赖;确切的c++结构并不重要。你可以打破它;point_of_parabaloid*只需要前向声明struct point_of_parabaloid;。但是打破这个循环并不能让你得到简洁的语法

看看你在c++ 17中的尝试,你已经可以在c++ 11中做类似的事情了。
例如:

#include<utility>
template<typename F>
struct S {
    S(F f): f{f} {}
    F f;
};
template<typename F>
struct T: F {
    T(F f): F{f} {}
};
int main() {
    auto l = [](){ ; };
    S<decltype(l)> s{l};
    s.f();
    T<decltype(l)> t{l};
    t();
}

如果需要,可以将丑陋的decltype隐藏在工厂方法后面:

template<typename L>
static auto create(L l) {
       return S<decltype(l)>{l};
}

关于这个的限制:

struct Y { auto x = [] { ; }; };

不是因为lambda。相反,这是因为auto占位符。根据标准,它不能用于声明非静态数据成员。
我猜原因是静态数据成员的类型在编译时就知道了(迟早必须放入唯一的定义),而非静态数据成员的类型可能需要在运行时解决。例如,想象一个if/else语句,其中使用两个不同的lambda来初始化对象。