Alex Rivera | Logout

Achieving clean lambda functions in C++11

Asked 2011-10-21T00:42:24.883
9

I've been playing around a lot with the new C++11 lambda's, and the requirement to fully specify the template argument is a real drag. The syntax I would like to be using is something similar to the following:

#include <vector>
#include <algorithm>

struct foo
{
    void bar() {}
};

int main()
{
    vector<foo> v(10);

    for_each(v.begin(), v.end(), [](f) {f.bar();});
                                   ^^^
}

Is there any way to get anything approximately close to this? Boost's Phoenix library is OK, but the syntax for calling member functions requires lots of boiler plate - I guess I'm after C++11's ease of calling member functions coupled with Phoenix's automatic deduction of type.

Current idea

I have gotten it down to this syntax:

vector<foo> x(1);
vector<bar> y(1);
for_each(x.begin(), x.end(), [](_a f) {f->f();});
for_each(y.begin(), y.end(), [](_a b) {b->b();});

Which works, but you have to add the capability per type (eg. ADD_AUTO_LAMBDA_SUPPORT(foo);). It also has the limitation that all supported types can not have any ambiguous members.

The full code for that is:

#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

struct foo
{
    foo() : x(3) {}
    int x;
    void f() { cout << x << endl;}
};

struct bar
{
    bar() : y(133.7) {}
    double y;
    void b() { cout << y << endl;}
};

struct combo : foo, bar { };

struct _a
{
    _a(foo& f) : offset(reinterpret_cast<combo*>(&f)) {}
    _a(bar& b) : offset(reinterpret_cast<combo*>((char*)&b - 2*sizeof(foo))) {}

    combo* operator->() { return offset; }

private:
    combo* offset;
};

int main()
{
    vector<foo> x(1);
    vector<bar> y(1);

    for_each(x.begin(), x.end(), [](_a f) {f->f();});
   
Edit
Report

1 Answer

2

So, presumably in the case of the following:

std::array<int,10> a;
for_each(begin(a),end(a),[](auto i){ /* ... */ });

You want the compiler to figure out that the lambda takes an int and basically read this as:

for_each(begin(a),end(a),[](int i){ /* ... */ });

The issue is that the type of the lambda affects the type of the for_each template instantiation, which might choose a different specialization, which could in turn require a different type deduction for the lambda parameter. So there is simply no reasonable way for the compiler to use the algorithm code to automatically deduce the type of the arguments you pass in.

Anyway, at least for the for_each algorithm you don't need this, just use the range for loop:

for(auto i:a) { /* ... */ }

And in other places use decltype:

transform(begin(a),end(a),begin(a),[](decltype(*begin(a)) i) { return 2*i; });
answered 2011-10-21T19:40:09.413

Your Answer