# Assigning lambdas

This topic is 2262 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Since the new C++ standard became accessible and implemented, I've been looking at ways to play a bit with it for integration. Although I've never really been on this functional programming as silver bullet bandwagon, I agree the ability to define functions on the fly is pretty much better than having to deal with the function pointers. Not to mention capture lists, which I'm considering promoting to the next best thing after sliced bread.

However, I'm afraid I don't understand something - the way functions are supposed to be passed around in VC2010.

I want to thank Washu for his article on functional programming. From there, I get the idea that functors work just like everything else. They can be passed by reference such as in [font=courier new,courier,monospace]MulticastEvent::AddHandler[/font] or by value, by storing in [font=courier new,courier,monospace]std::vector<EventSignature>[/font].
Great, but I'm having some difficulty in understanding a behavior here.
Consider:
 #include <iostream> #include <functional> using namespace std; typedef function<void()> PrintFunc; void Nothing(const PrintFunc &blah) { blah(); } void Nothing_value(const PrintFunc blah) { blah(); } struct Callbacks { PrintFunc const& func; // (2) Callbacks(PrintFunc const& call) : func(call) { } }; int main() { auto lines = []() { cout<<"- - - - - -"<<endl; }; auto dots = []() { cout<<". . . . . ."<<endl; }; Nothing(lines); Nothing_value(dots); { Callbacks one(lines); // (1) one.func(); } { Callbacks two(dots); two.func(); } return 0; } 
Everything seems to be fine up to line (1). Here, I suppose I have a complex function taking lots of callbacks I want to encapsulate in a single struct, similarly to how C# dispatches events via delegates as far as I've understood.
The result of this code is that the reference contained in the struct won't be initialized correctly. It is not initialized even immediately after creation. The situation shows in the debugger as attached.

However, if I change line (2) to value type, everything works as expected.

Is this a quirk in the compiler or am I missing something?

##### Share on other sites
[s]Works fine in GCC. Perhaps a compiler bug?[/s]

[edit: rather, it appears to work fine, but is actually incorrect. Read below for further explanation] Edited by rip-off

##### Share on other sites
VS10 is not entirely standards compliant in regards to lambdas (for instance, you can't assign a lambda directly to a C-style function pointer).

That being said, there is no way your code should work. lines is not an instance of std::function, but an instance of Visual C++'s built-in lambda type. You are then passing a temporary object of type std::function<void()>, and then assigning it to a reference, in effect, taking the address of a temporary value.

The proper fix would be to do as you did; change line (2) to be a value, and not a reference.

The fact that GCC works is actually surprising.

##### Share on other sites
Visual Studio, even the latest 2011 beta is next to useless for C++0x.

2010 is not even in contest.

To mess with C++0x, use GCC, at least for next several years. CLang also appears to be a good choice.

A different comparision (note the partial support, even for VS12.0, almost everything is way behind GCC). Edited by Antheus

##### Share on other sites

Visual Studio, even the latest 2011 beta is next to useless for C++0x.

2010 is not even in contest.

To mess with C++0x, use GCC, at least for next several years.

This still isn't a bug in VS10 or 11; they are both behaving properly. He's taking the address of a temporary value; since he's running a debug build, I assume that VC is zeroing out the temporary after it is out of scope, hence why it is 'empty' (null). I don't know why it works in GCC (and I reckon that it shouldn't) - it's probably not zeroing out the temporary; still undefined behavior, it just happens to work.

He needs to stop storing a reference and needs to store a value.

##### Share on other sites

He needs to stop storing a reference and needs to store a value.

At first I thought you're refering to 'Nothing'.

I missed the Callbacks. Yay for inconsistent naming conventions...

 PrintFunc const& func; // (2)

Above is very risky. It's correct and allowed, but very error prone. I also remember VS raising "cannot generate assignment operator" when doing that.

##### Share on other sites
Wow, great.
Please all, explain me in a way I can actually understand. I have never been given the opportunity of reading the official C/C++ ISO spec nor to spend my effort at looking for language design in details.

The fact that GCC works is actually surprising.
...
This still isn't a bug in VS10 or 11; they are both behaving properly.
Formally problem solved: so much for designing a language that now has two types of lambdas.
What is a correct syntax?

Visual Studio, even the latest 2011 beta is next to useless for C++0x.
...
Above is very risky. It's correct and allowed, but very error prone. I also remember VS raising "cannot generate assignment operator" when doing that.
I suppose I will change C++11 next to useless for me. But anyway, what's wrong and risky? I took the syntax from Washu's article. I now see that article works on very subtle details (besides there's no [font=courier new,courier,monospace]AddDelegate[/font]) functions and structs are supposed to be blindly cast there.
And to be completely honest, this is what I'd suppose it had to work for something properly useful.
Even the way types are supposed to be extracted from lambdas are fairly odd to me.

I mean, everybody talking about those things and then what I found out is that even GCC - which actually does the expected thing - is formally wrong?
This whole thing starts to smell like nonsense to me.

##### Share on other sites

Wow, great.
Please all, explain me in a way I can actually understand. I have never been given the opportunity of reading the official C/C++ ISO spec nor to spend my effort at looking for language design in details.

This line:
 Callbacks one(lines); // (1)
Constructs a Callbacks passing in a lambda. Since lambda is not a valid type for the constructor of Callbacks, a temporary object of type std::function<void()> is constructed instead and passed. Since you indicate the parameter as a CONSTANT REFERENCE, you can pass an unnamed temporary value (such as the std::function<void()> just constructed).

The instant that line is done evaluated the TEMPORARY VALUE that was constructed is destructed. Your Callbacks class now holds a reference to an unnamed temporary that no longer exists.

In fact, you can make it explicit (but with the same bug):
 Callbacks one(PrintFunc(lines)); // (1)

by changing this line:
 PrintFunc const& func; // (2)
to
 PrintFunc func; // (2)
you cause your constructor to invoke the function copy constructor, taking the unnamed temporary you passed and copying it. Thus avoiding holding on to a reference to a soon to be dead object.

Thus the corrected code:
 #include <iostream> #include <functional> using namespace std; typedef function<void()> PrintFunc; void Nothing(const PrintFunc &blah) { blah(); } void Nothing_value(const PrintFunc blah) { blah(); } struct Callbacks { PrintFunc func; // (2) Callbacks(PrintFunc const& call) : func(call) { } }; int main() { auto lines = []() { cout<<"- - - - - -"<<endl; }; auto dots = []() { cout<<". . . . . ."<<endl; }; Nothing(lines); Nothing_value(dots); { Callbacks one(lines); // (1) one.func(); } { Callbacks two(dots); two.func(); } return 0; } Edited by Washu

##### Share on other sites
. But anyway, what's wrong and risky? I took the syntax from Washu's article.[/quote]

Take a simpler example:struct Foo { const std::string & s; Foo(const std::string * str) : s(str) {}; } Foo f("Hello World"); // string is const char *

When Hello World gets passed into function, it's implicitly converted into std::string using the std::string::string(const char *) constructor, thereby creating a temporary. This temporary is then stored in s. It ceases to exist once the constructor ends.

Same happens above. lambda is not an function<>, but it gets converted into one with same flaws as above.

Implicit conversion occurs because constructor accepts *const* reference. It it merely accepted 'PrintFunc &' without const, implicit conversion shouldn't be possible and should raise an error or warning.

Storing objects by reference this way is "risky" precisely because of implicit conversions. Also because one cannot properly implement assignment operator, meaning objects storing references are non-copyable.

As mentioned, it's not strictly wrong as far as C++ is concerned, it's just up to you to make sure references remain valid in same way compiler won't complain about invalid pointers.

##### Share on other sites
I guess I have to apologize. I clearly have an excess of right-brain, intuitive, big-picture thinking. When I asked what's wrong with that, I didn't have the need to get explanations on why the temporary goes out of scope.
Seriously, I have been thinking at this the whole night and there are two cases

1. The language/compiler supports lambdas properly
2. Or it does not - like it's the case here

Now, it's clear at this point what was going on, so the rest is mostly rant. Or maybe not.

Works fine in GCC. Perhaps a compiler bug?
I mean seriously... we are bashing even the expected thing just because we want to be formally correct?
Because in my opinion what GCC is doing is The Right Thing and I don't think they have made it work because of a misconception, an error or a bug. I think it's the right thing to do if we claim to have support for "functional programming" in some language - define a function as you want - you don't change what it is.

My problem here is that I never figured out that the compiler would have cast something in the first place and yes, it was clear to me there were different types going to clash. But heck, we are talking about function pointers!
 struct Callbacks { void (*func)(void); // (2) Callbacks(void (*func)(void)) : func(call) { } }; We are not talking about some strange object thing around... that's function pointers at their core but ok, say they are some kind of objects, I would expect, from a properly implemented compiler -

1. 1
Rutin
19
2. 2
3. 3
JoeJ
15
4. 4
5. 5

• 21
• 19
• 11
• 13
• 17
• ### Forum Statistics

• Total Topics
631697
• Total Posts
3001764
×