Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ equivalent of C#'s Func<T, TResult>

The following code computes the average of a particular property of T in the items collection:

public double Average<T>(IList<T> items, Func<T, double> selector)
{
    double average = 0.0;

    for (int i = 0; i < items.Count; i++)
    {
        average += selector(items[i])
    }

    return average / items.Count;
}

I can then call this with a lambda expression:

double average = Average(items, p => p.PropertyName);

How would I go about doing this in c++? Here's what I have so far:

template <typename T>
double average(const vector<T>& items, ?)
{
    double average= 0.0;

    for (int i = 0; i < items.size(); i++)
    {
        average += ?;
    }

    return average/ items.size();
}

How might I go about calling this with a c++ lambda?


Edit: Thank you all very much, here's what I ended up with:

template <typename T>
double average(const vector<T>& items, function<double(T)> selector)
{
    double result = 0.0;

    for (auto i = items.begin(); i != items.end(); i++)
    {
        result += selector(*i);
    }

    return result / items.size();
}

And in main():

zombie z1;
z1.hit_points = 10;

zombie z2;
z2.hit_points = 5;

items.push_back(z1);
items.push_back(z2);

double average = average<zombie>(items, [](const zombie& z) {       
    return z.hit_points;
});
like image 393
aligray Avatar asked Jun 10 '11 12:06

aligray


2 Answers

The equivalent thing would be a std::function<double(T)>. This is a polymorphic function object which may accept any function object that has the correct operator(), including lambdas, hand-written functors, bound member functions, and function pointers, and enforces the correct signature.

Do not forget that in C#, the Func interface (or class, I forget) is written as Func<T, Result>, whereas C++'s std::function is written as result(T).

Oh, in addition, if you don't have C++0x, there's one in TR1 and also one in Boost, so you should easily be able to access it.

like image 52
Puppy Avatar answered Sep 18 '22 20:09

Puppy



template <typename T, typename Selector>
double average(const vector<T>& items, Selector selector)
{
    double average= 0.0;

    for (int i = 0; i < items.size(); i++)
    {
        average += selector(items[i]);
    }

    return average / items.size();
}

You can use anything callable and copyable as a selector.

like image 22
Konstantin Oznobihin Avatar answered Sep 16 '22 20:09

Konstantin Oznobihin