2012-02-01 18 views
15

少し初心者ご質問に申し訳ありません。ベクトルとペアのベクトルがありますC++ std ::ペアのベクトル変換 - >最初から新しいベクトル

typedef std::vector <int> TItems; 
typedef std::vector < std::pair <int, int> > TPairs; 

はどのようにファンクタを設計するために一歩

int main() 
{ 
TItems items; 
TPairs pairs; 

pairs.push_back (std::make_pair(1,3)); 
pairs.push_back (std::make_pair(5,7)); 

std::transform(items.begin(), items.end(), items.begin(), comp (&pairs)); 

return 0; 
} 

に別のベクトルにペアですべての最初の項目を変換する方法はありますか?

class comp 
{ 
private: 
    TPairs *pairs; 

public: 
    comp (TPairs *pairs_) : pairs (pairs_) { } 

    unsigned int operator() (const unsigned int index) const 
    { 
     return (*pairs)[index].second != pairs->end(); //Bad idea 
    } 
}; 

おそらくラムダ式とループのないユーザーフレンドリーな方法があります。ご協力いただきありがとうございます。

答えて

3

それはすでにライブラリ関数として提供していますので、私は本当に、あなたがファンクタとしてstd::getを使用したいです!

私たちがこの行を書くことができたらうれしいですね!

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

...しかし、それよりも少しひどいです。あなたは、使用するget明確にする必要があります。

int main() { 
    std::vector<int> items; 
    std::vector<std::pair<int, int>> pairs; 

    pairs.push_back(std::make_pair(1, 3)); 
    pairs.push_back(std::make_pair(5, 7)); 

    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), 
       (const int& (*)(const std::pair<int, int>&))std::get<0>); 

    return 0; 
} 

問題は、それがペアの任意の並べ替えのために働くように、パラメータとして1 pair&、2 const pair&、および3 pair&&を取るために、std::getis overloadedです入力として。残念ながら、オーバーロードが私たちの元の行ので

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

利回り

error: no matching function for call to ‘transform(std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, std::back_insert_iterator<std::vector<int> >, <unresolved overloaded function type>)’ 
    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 
                        ^
... 

/usr/include/c++/4.8/bits/stl_algo.h:4915:5: note: template argument deduction/substitution failed: 
note: couldn't deduce template parameter ‘_UnaryOperation’ 
    std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>); 

それはあなたが推測するときのために求めているstd::getのどの過負荷を知らない、std::transformのテンプレート型推論の邪魔になりますテンプレートはstd::transformのため、手動で指定する必要があります。関数ポインタを正しい型にキャストすると、コンパイラに "ちょっと、getconst&で、const&を返します。

少なくとも、私たちは標準ライブラリコンポーネントを使用していますか?

そしてラインの数の点で、それは他のオプションよりも悪化しません:kotlinski @ http://ideone.com/6dfzxz

+1

誰もが改善を考えることができますか?このように 'std :: get'をきれいに使うことができるのは素晴らしいことです。 ...本当に私は 'reinterperet_cast &)>(std :: get <0>)'を使用しているはずですが、それはもっと悪いようです... – NHDaly

+0

私はそれを考えると思います"ハード"キャストを、引数を指定できるラムダの中にラップされたget関数で置き換えることは可能です –

3

これはいかがですか?

items.reserve(pairs.size()); 
for (size_t it = 0; it < pairs.size(); ++it) { 
    items.push_back(pairs[it].first); 
} 

わかりやすくデバッグします。

+0

:おかげで、しかし、これは一般的なソリューションです。可能であれば、ループのないワンステップソリューションを探したいと思います。 – justik

+1

あなたはユーザーフレンドリーなものを求めましたが、C++の残虐行為で答えを投稿するのは間違いでしょう:) –

+0

+1:この場合は単純です。なぜ単純化すればループを避けるのですか? – stefaanv

15

まず、transformの3番目の引数にback_inserterを使用して、変換された値がベクトルの後ろにプッシュされるようにします。

第2に、1組のintを取り、最初のものを返すような関数を必要とします。これは、実行する必要があります。

int firstElement(const std::pair<int, int> &p) { 
    return p.first; 
} 

、一緒に作品を置くために:

TPairs pairs; 
pairs.push_back(std::make_pair(1, 3)); 
pairs.push_back(std::make_pair(5, 7)); 

TItems items; 
std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), 
       firstElement); 

をこのコードの後、itemsは1と5

+0

@ Freirich Raabe:ありがとうございます。 – justik

+2

カスタム関数の代わりに[std :: get <0>](http://en.cppreference.com/w/cpp/utility/tuple/get)を使用する巧妙な方法はありますか? – NHDaly

2

が含まれているどのようにstd::bindを使用してはどうですか?

std::transform(pairs.begin(), 
       pairs.end(), 
       std::back_inserter(items), 
       std::bind(&TPairs::value_type::first, std::placeholders::_1)); 

(非C++ 11のコードのためにboost::bindstd::bindを交換してください)

10

はfrerich年代やC++ 03のためのkotlinskiの回答を参照してください。ラムダと

C++ 11解決策:

std::transform(pairs.begin(), 
       pairs.end(), 
       std::back_inserter(items), 
       [](const std::pair<int, int>& p) { return p.first; }); 
+0

おっと、私は「ラムダなし」の要件に気がつかなかったが、それがなぜ簡単で言語の一部であるのか? – stefaanv

+0

私は、コンパイラの制限や職場の要求のために、ここの人のほとんどが実際に使用できるC++言語の一部ではないと考えています。 –

関連する問題