25

vector<T>aを に変換できる射影関数を作成しようとしていvector<R>ます。次に例を示します。

auto v = std::vector<int> {1, 2, 3, 4};
auto r1 = select(v, [](int e){return e*e; }); // {1, 4, 9, 16}
auto r2 = select(v, [](int e){return std::to_string(e); }); // {"1", "2", "3", "4"}

最初の試み:

template<typename T, typename R>
std::vector<R> select(std::vector<T> const & c, std::function<R(T)> s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

しかし、

auto r1 = select(v, [](int e){return e*e; });

私は得る:

エラー C2660: 'select': 関数は 2 つの引数を取りません

私は明示的に仕事に電話select<int,int>しなければなりません。型が冗長なので、私はこれが好きではありません。

auto r1 = select<int, int>(v, [](int e){return e*e; }); // OK

2 回目の試行:

template<typename T, typename R, typename Selector>
std::vector<R> select(std::vector<T> const & c, Selector s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

結果は同じエラーで、関数は 2 つの引数を取りません。この場合、実際には 3 番目の型引数を指定する必要があります。

auto r1 = select<int, int, std::function<int(int)>>(v, [](int e){return e*e; });

3 回目の試行:

template<typename T, typename R, template<typename, typename> class Selector>
std::vector<R> select(std::vector<T> const & c, Selector<T,R> s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

為に

auto r1 = select<int, int, std::function<int(int)>>(v, [](int e){return e*e; });

エラーは次のとおりです。

'select' : 'Selector' のテンプレート引数が無効です。クラス テンプレートが必要です

為に

auto r1 = select(v, [](int e){return e*e; });

エラー C2660: 'select': 関数は 2 つの引数を取りません

(最後の 2 つの試行が特に優れているわけではないことはわかっています。)

select()このテンプレート関数を最初に書いたサンプル コードで機能するようにするにはどうすればよいですか?

4

2 に答える 2

34

オプション1:

基本的decltype()な使い方:

template <typename T, typename F>
auto select(const std::vector<T>& c, F f)
    -> std::vector<decltype(f(c[0]))>
{
    using R = decltype(f(c[0]));
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c), std::back_inserter(v), f);
    return v;
}

オプション #2:

基本的std::result_of<T>な使い方:

template <typename T, typename F, typename R = typename std::result_of<F&(T)>::type>
std::vector<R> select(const std::vector<T>& c, F f)
{
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c), std::back_inserter(v), f);
    return v;
}

オプション #3:

高度なdecltype()使用法と完全転送(注*を参照):

template <typename T, typename A, typename F>
auto select(const std::vector<T, A>& c, F&& f)
    -> std::vector<typename std::decay<decltype(std::declval<typename std::decay<F>::type&>()(*c.begin()))>::type>
{
    using R = typename std::decay<decltype(std::declval<typename std::decay<F>::type&>()(*c.begin()))>::type;
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c)
                 , std::back_inserter(v)
                 , std::forward<F>(f));
    return v;
}

オプション #4:

高度なstd::result_of<T>使用法と完全転送(注*を参照):

template <typename T, typename A, typename F, typename R = typename std::decay<typename std::result_of<typename std::decay<F>::type&(typename std::vector<T, A>::const_reference)>::type>::type>
std::vector<R> select(const std::vector<T, A>& c, F&& f)
{
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c)
                 , std::back_inserter(v)
                 , std::forward<F>(f));
    return v;
}

* 注:オプション #3 と #4 は、std::transformアルゴリズムが関数オブジェクトを値で受け取り、それを非 const 左辺値として使用することを前提としています。typename std::decay<F>::type&これが、この奇妙な構文が見られる理由です。関数オブジェクトが関数自体の中で呼び出され、結果の型がコンテナーのテンプレート引数として使用されない場合 (最も外側selectのものを使用する目的で)、正しい移植可能な構文は、戻り値の型を取得する方法は次のとおりです。 std::decay<T>

/*#3*/ using R = decltype(std::forward<F>(f)(*c.begin()));

/*#4*/ typename R = typename std::result_of<F&&(typename std::vector<T, A>::const_reference)>::type
于 2014-10-15T13:27:23.647 に答える