6

I want to return a lambda object from a function without casting it to a function pointer or function object. More specifically, I want to leave it to the client to decide whether or not to cast to a function object or retain the lambda as an anonymous function:

template<typename F> // F may be a std::function, boost::function, or lambda object
auto func(F f) -> decltype(???) // what do I put in here?
{
    return [=]()
    {
        return f(someParameter);
    }
}

This code doesn't work because I don't know what type to deduce. One option might be to copy the body of the lambda into the decltype call. Surely there is a better way!

My reasoning for wanting to do it this way is that I want to leave open the possibility of the compiler more intelligently inlining or unwrapping the lambdas. Does this reasoning make sense? If so, why, and when is it better simply to return std::function? Could this method ever be slower at compile time?

quant
  • 21,507
  • 32
  • 115
  • 211
  • Is your goal to bind arguments to a function? Could be best handled using `std::bind` – Anycorn Apr 03 '14 at 03:02
  • @Anycorn My goal is to reduce the creation of function of objects and calls to `std::bind`. I can't control what the client will do with the return value but I want to leave open the possibility of them minimising the amount of `std::bind`ing and creation of `std::function` objects. – quant Apr 03 '14 at 03:05
  • I don't think there is anything particularly bad about returning `std::bind`, if it's implemented like `boost::bind` compiler will have no problem having access to body of `F`. – Anycorn Apr 03 '14 at 03:28
  • Care to add C++1y tag to this question? Because C++1y makes it easy... – Yakk - Adam Nevraumont Apr 03 '14 at 03:45

2 Answers2

9

In C++11 you cannot do this. You can do a few things that are close to it, but not this.

Basically, the only way to extract a type of a C++11 lambda is to deduce it from an instance of the type, and you cannot name the type in an unevaluated context. So a function cannot return a type whose type depends on the type of a lambda. (Unless said lambda is declared, with body, prior to the function's declaration, which is not useful in this case). You can write a functor that is a manual function object, or use std::bind which does that for you.

You can have it evaluate some other functor you also pass in with the lambda, but that gets awkward (especially in C++11 where such functors either have to type erase, or have to be an old-school functor written "manually" as a struct or class).

One of the features added in C++1y makes it easy, however:

template<typename F, typename T>
auto func(F f, T t) {
  return [=]() {
    return f(t);
  };
}
int main() {
  auto f = func( [](int x){ std::cout << x << "\n"; }, 7 );
  f();
  f();
}

Live example

It is possible your compiler already has C++1y support for this feature.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1
  • In C++11, type-erase with std::function<...>

  • In C++14 no need for decltype, so you can do:

    auto f() { return //lambda here }

That's all you can do for now.

Clang claims to have full c++14 support in its version 3.4, as the current draft is. Gcc has support full support for this in upcoming gcc 4.9, and partial support in gcc 4.8.

Germán Diago
  • 7,473
  • 1
  • 36
  • 59