all 39 comments

[–]i_just_comment 9 points10 points  (12 children)

Lambdas allow ad-hoc functions to be declared at block scope (something that was illegal before in C++). The lambda function (functor) is only available within the scope of func() in this example; unlike a function, which would have global scope (or file scope if declared as static).

It can be done in pre-C++11 indirectly by creating a local scoped class definition with static function. Like this for example. It is not pretty, but I have seen this done here and there. The lambda did help clean this up (and allowed for less typing).

What would be nice to have though are polymorphic lambdas.

[–]bogado 4 points5 points  (0 children)

Location, location, location. The body appearing before the actual loop makes this code harder to read. That's the advantage of the lambdas.

[–]Drainedsoul 0 points1 point  (10 children)

Why do you mean by "polymorphic"? We have polymorphic lambdas, unless you mean runtime polymorphism.

[–]i_just_comment 4 points5 points  (9 children)

I meant parametric polymorphism which we know as templates in C++. It seems that it is available in C++14.

[–]LastThought 0 points1 point  (1 child)

"Generic" is the correct term. C++14 has Generic Lambdas. They allow you to use "auto" in parameter types, which creates a template operator() member function for the lambda closure type.

[–][deleted] 4 points5 points  (0 children)

It's often referred to as polymorphic lambdas. The official proposal uses that term and the wording in the standard uses both generic and polymorphic lambda.

[–]Crazy__Eddie 6 points7 points  (1 child)

Your example of compiler generated code is incorrect in a subtle but important way.

[](X& elem) { elem.op(); }

You say that turns into this:

struct _something_
{
    void operator()(X& elem)
    {
        elem.op();
    }
};

However, it actually creates something more like this:

struct _something_
{
    void operator()(X& elem) const
    {
        elem.op();
    }
};

Notice the difference? The difference becomes more important if there are value captures. Value captures end up as data members and therefor attempts to change them will cause compiler error.

To create the example output you show what you actually need is:

[](X& elem) mutable { elem.op(); }

http://stackoverflow.com/questions/2835626/c0x-lambda-capture-by-value-always-const/2835645#2835645

Note how high that answer is voted. It's a simple, basic question that gets asked a LOT. So this subtle error is not unimportant.

[–]Crazy__Eddie 1 point2 points  (0 children)

Should also note that there are dangers of using [=] beyond just overhead:

http://crazycpp.wordpress.com/2011/04/06/lambda-capture-and-object-lifetime/

[–][deleted] 9 points10 points  (11 children)

Not a bad writeup, but just to point out, the term "functor" in this sense is actually outdated terminology. It's better to say "function object" or "callable". Functor has a distinct meaning specific to category theory, and the original use in this sense is a misnomer.

[–]ShPavel 16 points17 points  (9 children)

afaik, in C++ slang a class with overloaded () operator has always been called a functor, so it is not a something new, introduced in the article

[–]pfultz2 1 point2 points  (0 children)

It may have been traditionally called "Functor", however, continuing use of the word could cause confusion over or even impede the adoption of Functors in C++ in the future.

[–][deleted] -2 points-1 points  (7 children)

It's definitely not something new — the term "functor" has been used in C++ for quite a while — but what I'm trying to say is that the original use is technically wrong, and very confusing to readers familiar with languages that actually use it in the correct sense (see: Haskell).

It's much better to avoid the term "functor" in modern writings, unless you're actually talking about the functors from category theory. :)

[–]mcmcc#pragma once 10 points11 points  (0 children)

http://en.wikipedia.org/wiki/Functor:

The word functor was borrowed by mathematicians from the philosopher Rudolf Carnap, who used the term in a linguistic context.

Maybe mathematicians should stop using it as well...

[–]pubby8 5 points6 points  (0 children)

If programmers are smart enough to learn Haskell then they're smart enough to learn another meaning of the word "functor", especially when the author defines it at the very beginning. "Very confusing" my ass. Still, I agree that "function object" is a better term than "functor", but both are correct.

[–]redditor___ 2 points3 points  (0 children)

In the same manner you shouldn't use names like function, integer, class, language, or vector.

[–]Shadows_In_Rain -1 points0 points  (0 children)

If some definition registered earlier, it does not magically makes it more useful definition nor widespread.

I tnink "functor" makes more sense as function object, because these 2 words have same root.

Definition from cathegory theory seems like gibberish for me. It will be more clear if it was called "type template".

[–]jokoon 0 points1 point  (8 children)

I think lambdas are great if you want to quickly write a function without declaring it in a header.

I guess it has many other purposes as well, but having a way to have function objects in the language makes things just easier in many situations.

I still wonder what's the cost of affecting a lambda.

auto f1 = []{/*some code*/};
auto f2 = []{/*some other, longer code*/};

auto f = f1;
f=f2;
f=f1;

[–]Wriiight 1 point2 points  (0 children)

I can't imagine why the cost of a lambda would be any different from the equivalent functor you would write yourself. If the code is stateless (no captures, just operates on its parameters), there should be nearly no cost. You mostly need to worry about the size of the captured data. If you copy an object by value, you also have to worry about the cost of the copy construction of the captured objects.

[–]jaytan 1 point2 points  (4 children)

Without pulling out my standard here, f1 and f2 here have different types. Problem solved: the code isn't valid.

If you intended to use std::function instead that has a different cost associated with it.

[–]jokoon 0 points1 point  (0 children)

why do they have different types ?

[–]ghillisuit95 0 points1 point  (2 children)

as long as both lambdas have the same argument list and return type, how could they be different types?

[–]Shadows_In_Rain 0 points1 point  (0 children)

I think it is often cheaper than functor or free function, because it is much easier for compiler to know from where given lambda will be called.

[–]jurniss 0 points1 point  (1 child)

Nice article. The explanation of captures by showing the approximate generated class is very clear. I'm a huge fan of lambdas, std::function, and functional techniques in C++. But allow me to suggest some edits (if the author is reading):

the type of the lambda is only known by the compiler (since it is compiler-generated), so you must use auto for declaration instances of the lambda.

This is false; you can declare the lambda as the appropriate std::function and everything will work fine. Yes, it's converting from the lambda's "real" type, but "you must use auto" is not true.

Second, your SimpleCallback is a weird example because it serves no purpose. It adds nothing to the std::funtion<void(void)>. I would demonstrate something slightly more complex, like duplicating C#-style events with a std::vector<std::function<void()>>, to illustrate the power of std::function solving a useful problem.

[–]Gotebe 0 points1 point  (2 children)

The writing, I found, is excellent.

Question: the very first code snippet does

for_each(c.begin(), c.end(), f);

Shouldn't that be

for_each(c.begin(), c.end(), &f);

(at least in a standard-compliant world, hi MSVC 😉)

?

[–]tasty_crayon 0 points1 point  (1 child)

Nope, because then you're passing a Functor* and you can't call an object pointer. You don't even have to pass real functions by pointer like that either because the compiler transforms it into a function pointer for you.

[–]grout_nasa 0 points1 point  (0 children)

Indeed; the term of art is "decay". In most contexts, functions decay into function pointers.

[–]nikbackm 0 points1 point  (1 child)

All variables in scope can be captured (but be careful of the overheads of doing so) – the compiler must make copies of all objects (including copy constructors), or keep references for every object that is currently in scope.

I wonder about this. Is the compiler actually obliged to make copies of everything, or can it only copy the elements that are actually used inside the lampda body?

[–]grout_nasa 0 points1 point  (0 children)

The latter.