Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

capture member variable in labmda.

52 views
Skip to first unread message

Glen Stark

unread,
Mar 4, 2015, 8:24:50 AM3/4/15
to
Hi everyone.

Consider the following nonsense example (I'm not trying to do exactly
this, but it illustrates my question simply):

class Foo
{
void fun();
int m_val;
}

Foo::fun()
{
std::vector foos = get_some_other_foos();
auto non_matching_foo = [m_val](Foo f){return (f.m_val != m_val);};
if(std::find_if(foos.begin(), foos.end(), non_matching_foo))
std::cout << "found a different foo \n";
}
}

This won't compile because I can't capture m_val. I realize I can
capture 'this', but I don't really want to capture 'this', as in reality
I just need an int, not everything in the class, and I'd like that to be
clear in the lambda declaration.

Is there a solution to this? I'd also be interested in hearing why the
above isn't allowed.

Thanks

Glen

Victor Bazarov

unread,
Mar 4, 2015, 9:59:52 AM3/4/15
to
I don't have enough time to study the problem in depth it perhaps
deserves, but the first thing that came to mind is to provide a functor
instead of a lambda to the find_if and construct it with the 'm_val' as
its parameter. Something like this (pseudocode):

struct check_match {
int m_val2check;
check_match(int val) : m_val2check(val) {}
bool operator()(Foo f1) const { return f1.m_val != m_val2check; }
};
find_if(foos.begin(), foos.end(), check_match(this->m_val));

V
--
I do not respond to top-posted replies, please don't ask

Ben Bacarisse

unread,
Mar 4, 2015, 11:39:12 AM3/4/15
to
Glen Stark <ma...@glenstark.net> writes:

> Consider the following nonsense example (I'm not trying to do exactly
> this, but it illustrates my question simply):
>
> class Foo
> {
> void fun();
> int m_val;
> }
>
> Foo::fun()
> {
> std::vector foos = get_some_other_foos();
> auto non_matching_foo = [m_val](Foo f){return (f.m_val != m_val);};
> if(std::find_if(foos.begin(), foos.end(), non_matching_foo))
> std::cout << "found a different foo \n";
> }
> }
>
> This won't compile because I can't capture m_val. I realize I can
> capture 'this', but I don't really want to capture 'this', as in reality
> I just need an int, not everything in the class, and I'd like that to be
> clear in the lambda declaration.

You can only capture automatic variables and 'this'. So you could do:

void Foo::fun()
{
std::vector<Foo> foos = get_some_other_foos();

int this_m_val = m_val;
auto non_matching_foo = [=](Foo f){ return f.m_val != this_m_val; };

if(std::find_if(foos.begin(), foos.end(), non_matching_foo) != foos.end())
std::cout << "found a different foo \n";
}

--
Ben.

JiiPee

unread,
Mar 4, 2015, 1:09:51 PM3/4/15
to
How about using a reference to do it:

class Foo
{
public:
void fun();
int m_val;
};

void Foo::fun()
{
int& this_m_val = m_val;
auto la = [&](){ this_m_val = 55; };
la();
}

This would change m_val to 55;

Chris Vine

unread,
Mar 4, 2015, 3:21:04 PM3/4/15
to
Ben Bacarisse has given you the correct answer. Unless you create a
local variable, in a member function a lambda expression only captures
the 'this' pointer of the object of which the function is a member and
not its other members. So with C++11, in the lambda expression you
have to address object members through the this pointer if you don't
create local copies.

C++14 does have a simplification (?) for this, if you happen to use
gcc-4.9 or clang-3.4 (-std=c++14 or -std=c++1y), in the sense that it
makes it easier to create the local variable. Possibly gcc-4.8 also
supports it (I haven't tested). The syntax for this in C++14 is as
follows:

auto non_matching_foo = [m_val=this->m_val](Foo f){
return (f.m_val != m_val);
};

Of course, where the member 'm_val' is expensive to copy, you may be
better to stick to the C++11 approach and address the member through
the this pointer.

Chris

Luca Risolia

unread,
Mar 4, 2015, 8:46:27 PM3/4/15
to
Il 04/03/2015 14:24, Glen Stark ha scritto:
> class Foo
> {
> void fun();
> int m_val;
> };

^^^^^

> Foo::fun()
> {
> auto non_matching_foo = [m_val](Foo f){return (f.m_val != m_val);};
> }

> Is there a solution to this? I'd also be interested in hearing why the
> above isn't allowed.

One solution in C++14 is to use generalized lambda captures:

auto non_matching_foo = [m_val = m_val](Foo f){return (f.m_val != m_val);};

The reason why your code does not compile is that a lambda can capture
non-static local variables only. any "m_val" implicitly means
"this->m_val" for the compiler: if capturing were allowed, the Foo's
this pointer would be copied in the closure derived from the lambda,
resulting in the closure's viability obscurely tied to the Foo object's
lifetime, which is, honestly, undesirable.

Luca Risolia

unread,
Mar 4, 2015, 8:54:24 PM3/4/15
to
Il 04/03/2015 21:20, Chris Vine ha scritto:

> auto non_matching_foo = [m_val=this->m_val](Foo f){
^^^^^^

"this->" is superfluous and ugly.

Charles J. Daniels

unread,
Mar 4, 2015, 9:24:04 PM3/4/15
to
Capturing this is cheap. Hard to do better. Without an explicitly demonstrated need to optimize this section of your code, I wouldn't even waste the time thinking of alternate approaches.

Chris Vine

unread,
Mar 5, 2015, 5:13:29 AM3/5/15
to
It is clearer what it is doing. Whether it is "ugly" is in the eye of
the beholder.

Chris
0 new messages