使用模板参数推导

时间:2016-10-18 04:12:52

标签: c++ lambda auto c++17 type-deduction

以前,当 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)。

3 个答案:

答案 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->xthis->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来初始化对象。