以前,当 C ++ 11 可用时,我尝试使用auto
说明符和成员初始值设定项将lambda存储为类字段。这是一次失败的尝试:
struct Y
{
auto x = [] { ; };
};
错误:
错误:使用占位符' auto'
声明的非静态数据成员
尽管在定义类成员时已经知道lambda的大小(没有失去一般性,但没有捕获),但是不允许使用auto
说明符。为什么?不太明确的限制。
现在template argument deduction for class templates可用于GCC 7.0.0中继。我试着再做一次:
template< typename F >
struct X
: F
{
using F::operator ();
X(F && f) : F(static_cast< F && >(f)) { ; }
};
struct Y
{
X x = [] { ; };
};
但是我收到了一个错误:
错误:无效使用模板名称&#39; X&#39;没有参数列表
我怀疑,实施是部分甚至可能不一致。它是否允许我实现所需的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
)。
答案 0 :(得分:1)
如果事先知道lambda,你可以使用decltype
解决它:
auto lambda = [](){};
struct C {
decltype(lambda) member = lambda;
};
不完全漂亮,但确实有效。
我认为如果重写为:
,您的模板技术将会起作用 auto x = X([](){});
但是,gcc-7(快照)也不接受。我怀疑这是因为它仍在进行中。
[刚刚在20161014上构建的g ++ 7 trunk再次测试,然后上面的工作]
您可以使用制造商功能解决它
template <typename L>
struct X {
L member;
};
template <typename T>
auto make_x(T t) { return X<T>{t}; }
auto x = make_x([](){});
答案 1 :(得分:1)
您的问题是,您正在尝试在类定义中捕获成员函数外的this
。确切地说,double z = [&] { return x * x + y * y; }();
需要this->x
和this->y
。
你现在进入循环依赖:lambda的类型取决于捕获的是什么(this
,这是point_of_parabaloid*
)但point_of_parabaloid
取决于其成员的类型,包括非常lambda。
这是您设计中的循环依赖;确切的C ++结构并不重要。你可以打破它; point_of_parabaloid*
只需要struct point_of_parabaloid;
的前瞻性声明。但打破这个圈子并不会给你那种简洁的语法。
答案 2 :(得分:0)
通过查看您在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来初始化对象。