4

すべての意図と目的のために std::vector のように機能するカスタム ベクトル クラスがあります。シンプルなマップ機能を追加したい:

template <class T> class Vector
{
public:
    template<class mapFunction> Vector<typename mapFunction::result_type> map(mapFunction function)
    {
        Vector<mapFunction::result_type> result(_Length);
        for(UINT i = 0; i < _Length; i++)
        {
           result[i] = function(_Data[i]);
        }
        return result;
    }
    ...
}

使用法:

Vector<int> v(5);
for(int i = 0; i < 5; i++) v[i] = i;
auto mappedVector = v.map(function<double(int)>([](int a) { return a * 2.0; }));

これは機能しますが、ラムダ式から へのキャストの必要性を回避しようとしていstd::functionます。理想的にはv.map([](int a) { return a * 2.0; })); 、「make_pair」に似た「make_function」を記述して、テンプレート パラメーターの必要性を回避できることを認識しているだけですが、それでもすべてのラムダをキャストする必要があります。

std::function生のラムダ型から戻り値の型を抽出する方法がわからないため、 a にキャストします。したがって、私は使用してstd::function::result_typeいます。

私は以下がうまくいくと思っていましたが、そうではありません.コンパイラは、「returnType」のテンプレート引数を推測できないと不平を言うだけです:

template<class mapFunction, class returnType> Vector<returnType> Map2(mapFunction function)
{
    Vector<returnType> result(_Length);
    for(UINT i = 0; i < _Length; i++)
    {
        result[i] = function(_Data[i]);
    }
    return result;
}

私はそれがこれを行うことを認識してstd::transformいます (マップの本体を への呼び出しに簡単に置き換えることができますstd::transform) が、私の問題は実際にはテンプレート パラメーターを指定する正しい方法にあります。

4

1 に答える 1

11

まず、std::functionこの種の問題には使用しないでください。


最初に例を挙げて、簡単に説明します。クラスstd::vector全体を自分で実装したくないので、データを保存して機能を提供するためにを使用したことに注意してください;)。Vector

ライブワーキングコード

#include <iostream>
#include <vector>

//                /---------------------------------------------------------\
//                |                                                    //   |
template<typename T>                                                   //   |
class Vector {                                                         //   |
public:                                                                //   |
    std::vector<T> data;                                               //   |
                                                                       //   |
    template<class mapFunction>                                        //   |
    // Below: use C++11 trailing return type                                |
    auto map(mapFunction function) -> Vector<decltype(function(std::declval<T>()))>
    //                                       |                                   |
    {   //                                   |                                   |
        //                                   \-----------------------------------/
        //                                          |
        //                                          |
        //                 /-----------------------------------\
        //                 |                                   |
        using ReturnType = decltype(function(std::declval<T>()));

        Vector<ReturnType> result;

        auto size = data.size(); 
        result.data.reserve(size);

        for(std::size_t i = 0; i < size; i++)
        {
           result.data.push_back(function(data[i]));
        }

        return result;
    }
};

int main() {
    Vector<int> v;
    for(int i = 0; i < 10; ++i) {
        v.data.push_back(i);
    }

    auto newV = v.map([](int i) -> float {
        return (i * 2.0f) + 0.5f;       // Multiply by 2 and add 0.5
    });

    for(auto e : newV.data) {
        std::cout << e << std::endl;
    }
}

まず、C++11 の末尾の戻り型機能を使用します。パラメータを参照する必要があるため、このようにする必要がありますfunction。そのdecltype(function(std::declval<T>()))部分は面白い人です。その中で、私たちは基本的にコンパイラに尋ねます

function「 型の引数値が与えられた場合、 の戻り値の型は何になりますTか?」

次に、コンパイラは戻り値の型を指定し、それを result の最初のパラメーターに指定しますVector

後の部分はあなたのものと同じ本質を持っていますが、私は正確さと優雅さのためにそれらを修正しました.

C++14 では、末尾の戻り値の型を削除して、

template<class mapFunction>
auto map(mapFunction function) {
   using ReturnType = decltype(function(std::declval<T>()));
   Vector<ReturnType> result;

   ...

   return result;
}
于 2013-09-19T05:21:30.680 に答える