2

std::transformの問題は、一時オブジェクトの先頭と末尾の両方を取得できないことです。C++のPython風のマップ

私はPythonのようなマッピング関数をC++で実装したいと思います。これは型のベクトルで動作し、別の型(おそらく別の型)のベクトルにマップします。

これは私のアプローチです:

template <class T, class U, class UnaryOperator> 
std::vector<T> map(const std::vector<T>& vectorToMap, UnaryOperator operation) 
{ 
    std::vector<U> result; 
    result.reserve(vectorToMap.size()); 
    std::transform(vectorToMap.begin(), vectorToMap.end(), 
     std::back_inserter(result), [&operation] (U item) { return operation(item); }); 
    return result; 
} 

そして、これは(フィルタの戻り値の型は、その最初の引数の型です)私はこれを使用する方法の例です:

std::vector<std::shared_ptr<Cluster>> getClustersWithLength(const std::vector<Cluster>& clusterCollection, const int& length) 
{ 
    return map(filter(clusterCollection, [&length] (Cluster& cluster) { 
      return cluster.sizeY == length; 
     }), 
     [] (const Cluster& cluster) { 
     return std::make_shared<Cluster>(cluster); 
     }); 
    } 

私もこのコードの取得エラーメッセージは次のとおりです。

error: no matching function for call to 'map(std::vector<Cluster>, 
ClusterPairFunctions::getClustersWithLength(const 
std::vector<Cluster>&, const int&)::<lambda(const Cluster&)>)' 

note: candidate: template<class T, class U, class UnaryOperator> std::vector<_RealType> map(const std::vector<_RealType>&, UnaryOperator) 
std::vector<T> map(const std::vector<T>& vectorToMap, UnaryOperator operation) 
note: couldn't deduce template parameter 'U' 

あなたは私にいくつかの助けを与えることができ、私はそれを修正しますか?また、コンパイル時の静的アサーションを使用して、操作の種類(T t)がUかどうかを確認できますか?

Uの取り外しとstd::vector<typename std::result_of<UnaryFunction(T)>::type> result;と結果の宣言を置き換えるには、まだエラーが発生します。

src/ClusterPairFunctions.cc: In function 'std::vector<std::shared_ptr<Cluster> > ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)': 
src/ClusterPairFunctions.cc:130:14: error: could not convert 'map(const std::vector<_RealType>&, UnaryFunction) [with T = Cluster; UnaryFunction = ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(const Cluster&)>]((<lambda closure object>ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(const Cluster&)>{}, ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(const Cluster&)>()))' from 'std::vector<Cluster>' to 'std::vector<std::shared_ptr<Cluster> >' 
     return (map(filter(clusterCollection, [&length] (Cluster& cluster) { 
In file included from src/../interface/ClusterPairFunctions.h:5:0, 
       from src/ClusterPairFunctions.cc:1: 
src/../interface/../../../interface/HelperFunctionsCommon.h: In instantiation of 'std::vector<_RealType> filter(const std::vector<_RealType>&, UnaryPredicate) [with T = Cluster; UnaryPredicate = ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(Cluster&)>]': 
src/ClusterPairFunctions.cc:132:4: required from here 
src/../interface/../../../interface/HelperFunctionsCommon.h:52:15: error: no match for call to '(ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(Cluster&)>) (const Cluster&)' 
    if(predicate(*it)) result.push_back(*it); 
      ^
src/ClusterPairFunctions.cc:130:68: note: candidate: ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(Cluster&)> <near match> 
    return (map(filter(clusterCollection, [&length] (Cluster& cluster) { 
                    ^
src/ClusterPairFunctions.cc:130:68: note: conversion of argument 1 would be ill-formed: 
In file included from src/../interface/ClusterPairFunctions.h:5:0, 
       from src/ClusterPairFunctions.cc:1: 
src/../interface/../../../interface/HelperFunctionsCommon.h:52:15: error: binding 'const Cluster' to reference of type 'Cluster&' discards qualifiers 
    if(predicate(*it)) result.push_back(*it); 
      ^
src/../interface/../../../interface/HelperFunctionsCommon.h: In instantiation of 'std::vector<_RealType> map(const std::vector<_RealType>&, UnaryFunction) [with T = Cluster; UnaryFunction = ClusterPairFunctions::getClustersWithLength(const std::vector<Cluster>&, const int&)::<lambda(const Cluster&)>]': 
src/ClusterPairFunctions.cc:135:4: required from here 
src/../interface/../../../interface/HelperFunctionsCommon.h:64:9: error: could not convert 'result' from 'std::vector<std::shared_ptr<Cluster> >' to 'std::vector<Cluster>' 
    return result; 

答えて

3

あなたのコードはより一般的なものです:

template <template<class...>class Z=std::vector, class C, class UnaryOperator> 
auto fmap(C&& c_in, UnaryOperator&& operation) 
{ 
    using dC = std::decay_t<C>; 
    using T_in = dC::reference; 
    using T_out = std::decay_t< std::result_of_t< UnaryOperator&(T_in) > >; 
    using R = Z<T_out>; 
    R result; 
    result.reserve(vectorToMap.size()); 
    using std::begin; using std::end; 
    std::transform(
    begin(cin), end(cin), 
    std::back_inserter(result), 
    [&] (auto&& item) { return operation(declype(item)(item)); } 
); 
    return result; 
} 

C++ 11で上記の作業を行うには、末尾の戻り値のタイプ-> decltype(complex expression)を追加し、std::decay_t<whatever>typename std::decay<whatever>::typeに置き換えるか、独自のエイリアスを書き込む必要があります。

これらの手順:

using dC = std::decay<C>; 
    using T_in = dC::reference; 
    using T_out = std::decay_t< std::result_of_t< UnaryOperator&(T_in) > >; 
    using R = Z<T_out>; 

必要が私たちに与えてヘルパータイプ

template<template<class...>class Z, class C, class Op> 
struct calculate_return_type { 
    using dC = typename std::decay<C>::type; 
    using T_in = typename dC::reference; 
    using T_out = typename std::decay< typename std::result_of< Op&(T_in) >::type >::type; 
    using R = Z<T_out>; 
}; 

に移動するこの:

template <template<class...>class Z=std::vector, class C, class UnaryOperator> 
auto fmap(C&& c_in, UnaryOperator&& operation) 
-> typename calculate_return_type<Z, C, UnaryOperator>::R 
{ 
    using R = typename calculate_return_type<Z, C, UnaryOperator>::R; 
    R result; 
    result.reserve(c_in.size()); 
    using T_in = typename calculate_return_type<Z, C, UnaryOperator>::T_in; 

    using std::begin; using std::end; 
    std::transform(
    begin(c_in), end(c_in), 
    std::back_inserter(result), 
    [&] (T_in item) { return operation(decltype(item)(item)); } 
); 
    return result; 
} 

が、本当に、それは2016年で、への試みを行いますC++へのアップグレード14。 C++ 14では


Live exampleは、私はカレー風がSFINAEを行う機能(かどうかを検出するために、これらの両方が、 "可能であれば予備" を必要とするだけでなく

template<class Z, class T> 
struct rebind_helper; 
template<template<class...>class Z, class T_in, class...Ts, class T_out> 
struct rebind_helper<Z<T_in,Ts...>, T_out> { 
    using type=Z<T_out, Ts...>; 
}; 
template<class Z, class T> 
using rebind=typename rebind_helper<Z,T>::type; 

template<class Op> 
auto fmap(Op&& op) { 
    return [op = std::forward<Op>(op)](auto&& c) { 
    using dC = std::decay_t<decltype(c)>; 
    using T_in = dC::reference; 
    using T_out = std::decay_t< std::result_of_t< UnaryOperator&(T_in) > >; 
    using R=rebind< dC, T_out >; 
    R result; 
    result.reserve(vectorToMap.size()); 
    using std::begin; using std::end; 
    std::transform(
     begin(cin), end(cin), 
     std::back_inserter(result), 
     [&] (auto&& item) { return operation(declype(item)(item)); } 
    ); 
    return result; 
    }; 
} 

作品を見つけます.reserveが存在し、そうであれば予約し、それ以外の場合は気にしません)。

目は次のようになります。その後、コンテナを渡すことができ

auto fmap_to_double = fmap([](auto in){ return (double)in; }); 

、それはdoubleにその要素を再マップします。一方、常にベクトルを生成することは、価値のある単純化であるかもしれない。しかし、常にベクトルを消費するだけでは無意味に見えます。

+0

このコードはC++ 11では無効です。 –

+0

@AdamHunyadi Verbose C++ 11バージョンが追加されました。 – Yakk

+1

@AdamHunyadi Typosと残りのC++ 14のものが削除され、ライブのサンプルが含まれています。 – Yakk

1

代わりにテンプレートパラメータとしてUを有するので、あなたは、単にこのようなあなたの結果ベクトルを宣言することができます。

std::vector<typename std::result_of<UnaryFunction(T)>::type> 
+0

これでもエラーメッセージが表示されます。私は質問の編集として追加しました。 –

関連する問題