9

以下代码计算集合中特定属性的平均值Titems

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;
}

然后我可以用一个lambda表达式来调用它:

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

我将如何在 C++ 中执行此操作?这是我到目前为止所拥有的:

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();
}

我该如何用 c++ 调用它lambda


编辑:非常感谢大家,这就是我最终得到的结果:

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();
}

并在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;
});
4

4 回答 4

14

等效的东西是std::function<double(T)>. 这是一个多态函数对象,它可以接受任何具有正确的函数对象operator(),包括 lambdas、手写函子、绑定成员函数和函数指针,强制执行正确的签名。

不要忘记在 C# 中,Func接口(或类,我忘记了)写为Func<T, Result>,而 C++std::function写为result(T).

哦,另外,如果你没有C++0x,TR1里有一个,Boost里也有一个,所以你应该可以很容易地访问它。

于 2011-06-10T12:28:06.193 回答
4

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();
}

您可以使用任何可调用和可复制的内容作为选择器。

于 2011-06-10T12:27:44.737 回答
3
template <typename T>
double average(const vector<T>& items, double(*selector)(T))
{
    double average= 0.0;

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

    return average/ items.size();
}

请注意,这不是最好的方法,它只是最容易编写和理解的方法。正确的方法是使用仿函数,这样它也可以与 C++0x 的 lambda 表达式一起使用。

于 2011-06-10T12:22:30.687 回答
3

有很多方法,取决于您想要做什么,解决方案的通用性和可重用性,您可以接受的内存限制(即连续布局内存与一些链表等)。但这里是一个使用 C++03 的简单示例:

#include <vector>
#include <list>
#include <iostream>

template <typename Iter, typename Selector>
inline double
average (Iter it, Iter end, Selector selector)
{
    double average = 0.0;
    size_t size = 0;

    while (it != end)
    {
        average += selector (*it);
        ++size;
        ++it;
    }

    return size != 0 ? average / size : 0.0;
}

struct DoublingSelector
{
    template <typename T>
    inline T operator () (const T & item)
    {
        return item * 2;
    }
};

int main ()
{
    std::vector<int> data;
    data.push_back (1);
    data.push_back (3);
    data.push_back (5);
    std::cout << "The average is: " <<
        average (data.begin (), data.end (),
            DoublingSelector ()) << std::endl;
}

例如,假设您只能接受高级容器(而不是数组),这可能会容易得多。你可以通过抛出 C++0x 来获得 lambda,例如:

#include <vector>
#include <iterator>
#include <iostream>

template <typename C, typename Selector>
inline double
average (const C & items, Selector selector)
{
    auto it = std::begin(items);
    auto end = std::end(items);

    // Average is only meaningful on a non-empty set of items
    assert(it != end);

    double sum = 0.0;
    size_t size = 0;    

    for (; it != end; ++it)
    {
        sum += selector(*it);
        ++size;
    }

    return sum / size;
}

int main ()
{
    std::vector<int> data = { 1, 3, 5 };
    std::cout << "The average is: " <<
        average (data, [] (int v) { return v * 2; }) << std::endl;
}

这是你的选择 :-)

PS:是的,而且std::function(实际上是 C++0x 之前的 Boost 中的东西)可用于使您的算法成为非模板。否则,它只会限制您可以传入的“选择器”。

于 2011-06-10T12:38:08.853 回答