2011-10-29

c++: lambda example

A quick example of using lambdas in the new C++ spec.


One annoying aspect of API design I often bump into is implementing search functions on a custom container. It seems far too easy for the types of search behaviour to proliferate, leading to either an extensive API (i.e. having a variety of specific search calls on a class) or a flexible-but-awkward system (such as implementing search through a custom interface class). I was thrilled to see C++ finally get lambdas, which provide me an easy way to avoid those hassles.

Here's a quick custom container class that does nothing but implement a generic search function, which clients can extend with their own lambda behaviour. Note that this code is off the top of my head and might well have some bugs, so take it as a quick syntax reference and nothing more.

First, the house keeping details: Custom data and container classes.

class Data {
public:
Data() : mA(-1), mB(-1) { }

int mA, mB;
};

class Container {
public:
Container();

private:
std::vector<Data> mData;
};

Next, for convenience, we'll specify a standard search function and a method on Container to send it to. Now the container class looks like this:

class Container {
public:
// Define a standard function to use for search(). It takes a vector of Data and
// returns a const Data*.
typedef std::function<const Data* (const std::vector<Data>&)> SearchFunc;

public:
Container();

// Search for a specific datum. Use one of the default search functions supplied
// below (i.e. SEARCH_A) or pass in a lamba like so:
// const Data* d = aContainer.search([](const std::vector<Data>& a) -> const Data* {
// for (auto it=a.begin(), end = a.end(); it != end; ++it) {
// const Data& data = *it;
// return &data;
// }
// return nullptr;
// });
const Data* search(const SearchFunc &func = nullptr) const;

private:
std::vector<Data> mData;
};

For convenience we'll specify a few standard searches. In the header we might add...

// Answer the datum with the given A value
extern Container::SearchFunc SEARCH_A(const int& valueA);
// Answer the datum with the given B value
extern Container::SearchFunc SEARCH_B(const int& valueB);

...and implement them in the source as

Container::SearchFunc SEARCH_A(const int& valueA) {
return [&valueA](const std::vector<Data>& a) -> const Data*
{
for (auto it = a.begin(), end = a.end(); it != end; ++it) {
const Data& data = *it;
if (data.mA == valueA) return &data;
}
return nullptr;
};
}

Container::SearchFunc SEARCH_B(const int& valueB) {
return [&valueB](const std::vector<Data>& a) -> const Data*
{
for (auto it = a.begin(), end = a.end(); it != end; ++it) {
const Data& data = *it;
if (data.mB == valueB) return &data;
}
return nullptr;
};
}

And that's it. Easy, extensible, simple system for generic search behaviour.

header

source

No comments:

Post a Comment