views:

307

answers:

3

Hello,

I'm trying to work with lambda's in C++ after having used them a great deal in C#. I currently have a boost tuple (this is the really simplified version).

typedef shared_ptr<Foo> (*StringFooCreator)(std::string, int, bool)
typedef tuple<StringFooCreator> FooTuple

I then load a function in the global namespace into my FooTuple. Ideally, I would like to replace this with a lambda.

tuplearray[i] = FooTuple([](string bar, int rc, bool eom) -> {return shared_ptr<Foo>(new Foo(bar, rc, eom));});

I can't figure out what the function signature should be for the lambda tuple. Its obviously not a function pointer, but I can't figure out what a lambda's signature should be. The resources for lambda's are all pretty thin right now. I realize C++0x is in flux at the moment, but I was curious about how to get this to work. I also realize there are simpler ways to do this, but I'm just playing around with C++0x. I am using the Intel 11.1 compiler. Thanks

+6  A: 

The -> operator sets the return type of the lambda, in the case of no return type it can be omitted. Also, if it can be inferred by the compiler you can omit the return type. Like Terry said, you can't assign a lambda to a function pointer (GCC improperly allows this conversion) but you can use std::function.

This code works on GCC and VC10 (remove tr1/ from the includes for VC):

#include <tr1/tuple>
#include <tr1/functional>
#include <tr1/memory>

using namespace std;
using namespace std::tr1;

class Foo{};
typedef function<shared_ptr<Foo>(string, int, bool)> StringFooCreator;
typedef tuple<StringFooCreator> FooTuple;

int main() {
    FooTuple f(
        [](string bar, int rc, bool eom) {
            return make_shared<Foo>();
        }
    );

    shared_ptr<Foo> pf = get<0>(f)("blah", 3, true);
}
joshperry
Won't work - a lambda expression is not a function pointer. It is (conceptually) an anonymous functor class.
Terry Mahaffey
from the things I've read, the compiler should be able to figure it out and will let me know if it can't. I'll take a look at it. thanks.
Steve
@Terry hmm that's odd, because this code compiles and runs on GCC right now.
joshperry
@Steve, this could just be implementations lagging the standard, it's still pretty bleeding edge even though the standard has been ratified.
joshperry
@joshperry - I can verify that it doesn't work on the Intel compiler. Well, I guess lambda's are like the wild west right now.
Steve
@Steve, any specific error?
joshperry
VC10 doesn't have tuple yet, so I can't test it exactly as written, but you I make a similar example trying to assign a lambda to a function pointer, it doesn't compile (cannot convert from anonymous-namespace::<lambda0> to functionpointertype). Maybe tuple or gcc is doing something special, idk.
Terry Mahaffey
In fact it does have a tuple, and this same code works fine on VC10, just tried it.
joshperry
You're confusing me when you say "same code". Your original code doesn't compile on VC10, for the reason I said above (can't convert lambda to function pointer). I was wrong about tuple not being in VC10, though. Your updated version (using std::function) does compile.I'm not a language lawyer, but I think VC is correct here in not performing this conversion.
Terry Mahaffey
Terry, you're right. GCC actually has a conversion operator that is not part of the standard draft. So my first code snippet should not compile on a standards conforming compiler.
joshperry
"The -> operator sets the return type of the lambda, in the case of no return type it can be omitted" - it can also be omitted when return type can be inferred; "In your case you need to set the return type as shared_ptr<Foo>" - he doesn't, because the body of his lambda is a single `return` statement, which is precisely the context in which return type can be inferred.
Pavel Minaev
@joshperry - Thanks for all of the time and effort you put into this answer.
Steve
Thanks Pavel, for some reason the inference wasn't working for me at first, but with my latest code it is working so I'll update the answer. Steve, did you get it working on the Intel compiler?
joshperry
Yep, everything works as expected with your last example. Its faster than a function pointer too!
Steve
C++0x has conversion to function pointer for non-capturing lambdas now, see *§5.1.2/6* in the FCD.
Georg Fritzsche
+1  A: 

You should be able to store a lambda in a std::function. In your example, try storing it in a

std::function<std::shared_ptr<Foo>(std::string,int,bool)>

Don't forget about auto (although you won't be able to make an array of auto's, etc).

Terry Mahaffey
Do you by any chance know the header for std::function? Google isn't helping me...
Steve
also, what do you mean by auto?
Steve
std::function is in <functional>auto is another c++0x feature
Terry Mahaffey
bah, its failing on some crazy boost error about template instantiation. Thanks
Steve
I don't know about everyone else, but I had to disable some of the C++0x features from Boost (there's #defines to enable/disable them).
Eric Muyser
+3  A: 

From Visual C++ Blog

I mentioned storing lambdas in tr1::functions. But you shouldn't do that unless it's necessary, as tr1::function has some overhead. If you want to reuse a lambda, or simply want to give it a name, you can use auto.

Nikola Smiljanić
`auto` is of no help here, as it can't be used as a type parameter for a container like `vector`.
Pavel Minaev
That's true, I just wanted to mention the overhead.
Nikola Smiljanić
On the Intel compiler, the lambda with function is still faster than caching a function pointer. Approximately 3-5% faster from my tests. Thanks for the tip.
Steve