Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store lambda as a member using template arguments deduction

Previously, when C++11 became available I tried to store a lambda as a class field using auto specifier and member initializers. It was an unsuccessfull attempt:

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

Error:

error: non-static data member declared with placeholder 'auto'

Despite of size of lambda (w/o lost of generality, with capture) is known at time of definition of a class member, it not allowed to use auto specifier. Why? Not too clear restriction.

Now template argument deduction for class templates available in GCC 7.0.0 trunk. And I tried to do it again:

template< typename F >
struct X
    : F
{
    using F::operator ();
    X(F && f) : F(static_cast< F && >(f)) { ; }
};

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

But I get an error:

error: invalid use of template-name 'X' without an argument list

I suspect, that the implementation is partial or even maybe inconsistent. Will it allow me to achieve desired w/o type erasure (and dynamic allocation of a memory)?

Free non-member definition is allowed:

X x = [] { ; };

ADDITIONAL:

People asks what the problem I tried to solve? I need a terse syntax for in-class defined functors.

If I can write (following code is valid):

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);

Why can't I define an in-class lambda (say, for lazy evaluation of z)?

I don't need to capture something abnormal, just a class members (or this) as in point_of_parabaloid definition.

like image 790
Tomilov Anatoliy Avatar asked Apr 19 '26 16:04

Tomilov Anatoliy


1 Answers

You can work around it with decltype if the lambda is known before hand:

auto lambda = [](){};

struct C {
  decltype(lambda) member = lambda;
};

Not exactly pretty, but it works.

I think your template technique would work if rewritten as:

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

However, gcc-7 (snapshot) does not accept that either. I suspect that it is because it's still work in progress.

[just tested again with g++ 7 trunk built on 20161014, and then the above works]

You can work around it with a maker function

template <typename L>
struct X {
  L member;
};

template <typename T>
auto make_x(T t) { return X<T>{t}; }

auto x = make_x([](){});
like image 133
rollbear Avatar answered Apr 22 '26 07:04

rollbear