9

T次のコードは、itemsコレクション内のの特定のプロパティの平均を計算します。

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()これは、ラムダ、手書きの関数、バインドされたメンバー関数、関数ポインターなど、正しいを持っている任意の関数オブジェクトを受け入れ、正しい署名を適用できる多形関数オブジェクトです

C#では、Funcインターフェイス(またはクラス、私は忘れています)は、として記述されているFunc<T, Result>のに対し、C++では。std::functionとして記述されていることを忘れないでくださいresult(T)

また、C ++ 0xがない場合は、TR1とBoostに1つずつあるので、簡単にアクセスできるはずです。

于 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のラムダ式でも機能するようにすることです。

于 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をスローすることで、ラムダを取得できます。次に例を示します。

#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 に答える