17

For example, I can define a lambda function as

auto f = [](double value) {double ratio = 100; return value * ratio;}

Now I want to generate a function with the ratio an argument and return the lambda function like

auto makeLambda(double ratio) { return [=](double value) {return value * ratio;}; }

How to do it?

2
  • 1
    What's wrong with what you have? Commented Jun 26, 2014 at 13:23
  • 7
    @chris: It requires C++14 to deduce the function return type. Commented Jun 26, 2014 at 13:23

3 Answers 3

21

With C++14 function return type deduction, that should work.

In C++11, you could define another lambda (which can deduce the return type), rather than a function (which can't):

auto makeLambda = [](double ratio) {
    return [=](double value) {return value * ratio;};
};

As noted in the comments, this could be further wrapped, if you particularly want a function:

auto makeLambdaFn(double ratio) -> decltype(makeLambda(ratio)) {
    return makeLambda(ratio);
}
Sign up to request clarification or add additional context in comments.

3 Comments

You forgot to make the inner lambda capturing.
The example works in idone but failed in vc2013. VC2013 is still not c++11 enough.
If you want a function rather than a lambda, wrap the lambda in a function again: auto func(double x)->decltype(makeLambda(x)){return makeLambda(x);}
12

@disclaimer: this answer just adds extra arguments to @Slava's answer (but is too long for a comment).

You probably should not return a lambda, but a function pointer or a std::function.

Efficiency concerns asside (see below), the declaration of an API should tell you how to use it. A lambda is a temporary function - something designed to make sense where you use it (in a local context).

If you write this:

std::function<double( double )> makeFunction(double ratio);

Your code will be much more flexible (not depending on C++14), much better defined (you can look at the signature and know what it does) and future-proof (it is easy to understand the intent behind the API, which makes easy to extend later without screwing up client code).

If you write this:

auto makeFunction(double ratio);

You have to define it inline (I guess).

For an implementation similar to MikeSeymour's answer, you need to add an extra lambda, to avoid a limitation of the compiler. Reading an implementation with a lambda returning a lambda just to figure what the API returns, is a big no-no.

First, because it is non-obvious and obscure.

Second, it will impose on client code, an API that either needs a comment/explanatory note to make sense, or forces clients to read it's implementation to know how to use it.

If you cannot guarantee this is throw-away code, you will:

  • increase WTF/SLOC ratio of your code (code is not clear in purpose, if you need to read the implementation to figure out what it returns)

  • have something non-obvious, that you will have to maintain for the whole project. This is called cruft and is what makes sucky legacy code be sucky legacy code).

If you need to return a functor, you're better off returning a std::function; The return type practically screams "returning a functor".

If this is too inefficient for your needs, you can optimize/particularize it later) - for example, by returning a struct X { double operator()(double); } instance.

A note about being able to guarantee that this is not production code:

I've seen many cases where:

  • I was looking at horrible three-year old code, where people told me originally this was the prototype, but we showed the app to the clients, they asked for it "as it is", and now clients depend on it, but we don't have the time budget to clean it up.

  • I sent ugly prototype code to someone else (as in "we could do something that follows this algorithm") and saw it committed as a solution in source control later.

  • People wrote hacks over hacks because the code was already hacky and one more hack doesn't matter (that's a very common excuse actually).

Comments

4

You can return std::function<double( double )>. Calling it may have a cost of additional function call, which is insignificant in most cases.

5 Comments

This would be a good answer if you also described what the implications are (mainly for efficiency).
@Angew Do you have any pointers to info on that? I need to brush up on my C++11 :)
@JoachimIsaksson the biggest is that std::function uses a technique called "type erasure", and this incurs an indirection every call (often implemented as a virtual function).
@JoachimIsaksson What Simple says.
+1; I added an answer that basically supports this (too long for a comment).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.