64

Suppose I have a custom container class with a selection function like below:

template <typename T> class Container { public: // ... Container<T> select(bool (*condition)(const T&)) const; // ... }; 

As you can see, the select function takes a pointer to a condition function. This is a function that defines which items should be selected. So, an example use of this would be something similar to:

bool zero_selector(const int& element) { return (element == 0); // Selects all elements that are zero } 

Now if I have a container filled with, say s = { 1, 1, 0, 0, 1, 0, 1, 0 }, I could select a subset of these that would only contain zeroes using:

t = s.select(&zero_selector); // t = { 0, 0, 0, 0 } 

This is a bit clunky, and lambda expressions would make this much more elegant:

t = s.select([&] (int x) -> bool { return (x == 0); }); 

Is this possible? If so, what should my function prototype be for Container::select() to accept a lambda as one of its parameters?

If not, then how is something like std::for_each implemented that can use a lambda expression as one of its arguments? Everything I've found just gives examples of lambda functions and using std::function<> to pass them as parameters, but nothing explains how std::for_each works with lambda expressions.

Note that this code is for demonstration purposes only. I have tried implementing the same principles in the actual project and it doesn't work.

3 Answers 3

75

There's no need to add the knee-jerk [&]-capture. Your lambda doesn't need it:

[] (int x) -> bool { return (x == 0); } 

Captureless lambdas are convertible to the corresponding function pointer, so this should work out of the box.

That said, you should probably declare the select function to accept std::function, to which all lambdas are convertible, capturing or not:

Container<T> select(std::function<bool(const T&)> predicate) const; 
Sign up to request clarification or add additional context in comments.

2 Comments

What does <bool(const T&)> mean? A function taking one const argument of type T by reference and returning bool?
@Wilson: Yes, e.g. see here.
29

You need to declare your lambda as stateless (that is, with an empty capture specification [](int x)-> bool {...}) for it to be convertable to a function pointer.

5 Comments

Or use std::function, or make select a template
I tried your solution (on the exact code posted above by removing the &), and it doesn't work. It gives me error C2664 because it can't convert '`anonymous-namespace'::<lambda0>' to 'bool (__cdecl *)(const T &)'.
@teedayf, it's a newer addition to C++11. Visual Studio 2010 does not support it yet. And you would need to declare the lambda as [](const int &x) {...} to match the function pointer signature.
@MSN, Ah, I see. And yah, I tried the other prototype, and it didn't work either. So it's just not supported on VS2010 yet.
Should be in VS2011, though. They'll even deal with all the nasty STDCALL calling conventions, so you can pass stateless lambda's to e.g. SetWindowsHookEx
0

I'd opt for compile time resolution (template parameters) over run-time resolution (std::function):

  • No virtual function call. Normally I'd ignore the overhead but your example involves iterating through a container, which is the archetypical example of where we don't want unnecessary overhead!
  • Your class is already a template, so there's not really anything to be lost by including another template parameter, if anything it's easier.
  • May be inlined by the compiler.
  • No unnecessary function-signature constraints.

So I'd use:

template <typename T> class Container { ... template<typename F> Container<T> select(F fun) const { ... foo = fun(bar) ... } ... }; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.