2012-02-01 114 views
15

對不起,有點初學者的問題。有向量和雙矢量C++ std :: transform向量對 - >第一個到新的向量

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 
    } 
}; 

也許還有一些沒有lambda表達式和循環的用戶友好方法。謝謝你的幫助。

回答

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; 
} 

的問題是,std::getis overloaded取1 pair&,2 const pair&和3 pair&&作爲參數,使之適用於任何類型的對工作作爲輸入。不幸的是,重載得到的模板類型扣除std::transform的方式,所以我們最初的訂單

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的模板,所以你必須手動指定它。將函數指針轉換爲正確的類型告訴編譯器:「嘿,請使用超載,其中get需要const&並返回const&!」

但至少我們使用的是標準庫組件(yay)?

而且在線路的數量方面,它並不比其他選擇更糟糕: http://ideone.com/6dfzxz

+1

任何人都可以想到任何改進?能夠像這樣乾淨地使用'std :: get'會很棒。 ...真的,我應該使用'reinterperet_cast &)>(std :: get <0>)',但那似乎更糟糕... – NHDaly 2015-08-14 01:19:39

+0

我認爲它可以用包裝在一個lambda表達式中的get函數來替換「hard」類型轉換,其中可以指定參數 – 2015-10-29 10:47:22

3

這個怎麼樣?

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

很容易理解和調試。

+0

@ kotlinski:謝謝,但是這是一個通用的解決方案。如果可能的話,我想找到沒有任何循環的單步解決方案。 – justik 2012-02-01 10:26:51

+1

你問了一些用戶友好的東西,然後用一些C++暴行來發布答案會讓人誤解:) – 2012-02-01 10:28:34

+0

+1:在這種情況下最簡單。爲什麼避免循環,如果簡化? – stefaanv 2012-02-01 12:14:01

15

首先,您應該使用back_inserter作爲transform的第三個參數,以便將轉換後的值推送到該向量的後面。

其次,你需要某種函數,它需要一對整數並返回第一個。這應該這樣做:

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 2012-02-01 11:03:47

+2

有沒有什麼聰明的方式來使用[std :: get <0>](http://en.cppreference.com/w/cpp/utility/tuple/get)而不是你的自定義函數? – NHDaly 2015-08-13 23:56:54

2

如何使用std::bind

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

(由boost::bind非C++ 11的代碼替換std::bind

10

看到frerich的或kotlinski的答案爲C++ 03。

C++ 11的解決方案與拉姆達:

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

糟糕,我沒有注意到「沒有拉姆達」的要求,但爲什麼當它是直接的和語言的一部分? – stefaanv 2012-02-01 12:15:16

+0

我相信這不是C++語言的一部分,因爲這裏大多數人可以真正使用C++語言(無論是由於編譯器限制還是由於工作場所的一些要求)。 – 2012-02-01 12:52:22