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();});
for_each(y.begin(), y.end(), [](_a b) {b->b();});
}
You could then use some template and preprocessor magic to generate both _a
and combo
, but the issue comes when you have ambiguous names (eg. a third struct with a b()
function - you need a way to disambiguate them that I can't think of at the moment.
Note: I fully agree that [](auto f){ ... }
would be very desirable!
While we don't have that, what about good old typedef
? It just adds one line, is very "low-tech" and makes the lambda easy to read:
typedef const map<key_type, value_type>::value_type& λp_t;
for_each(m.begin(), m.end(), [&](λp_t x) {...});
You can use decltype:
for_each(m.begin(), m.end(), [&](decltype(*m.begin()) x){...});
But it really, really sucks that you cant use auto in anonymous lambdas.
Update:
You could also do
#define _A(CONTAINER_NAME) decltype(*CONTAINER_NAME.begin())
for_each(m.begin(), m.end(), [&](_A(m) x) { ... });
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; });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With