2012-02-01 5 views
15

थोड़ा सा शुरुआती प्रश्न के लिए खेद है। वेक्टर और जोड़े के वेक्टर हैंसी ++ 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; 
} 

में एक और वेक्टर के लिए जोड़ी के सारे पहला आइटम को बदलने के लिए कैसे एक functor डिजाइन करने के लिए कोई तरीका है?

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 functor के रूप में उपयोग करना चाहते हैं, क्योंकि यह पहले से ही एक पुस्तकालय समारोह के रूप में प्रदान की जाती है !!

अगर हम इस लाइन को लिख सकते हैं तो यह अच्छा नहीं होगा !?

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

... लेकिन यह उससे थोड़ा अधिक भयानक है। std::getis overloaded 1. pair& लेने के लिए, 2. पैरामीटर के रूप में const pair&, और 3. pair&&, इतना है कि यह जोड़ी किसी भी प्रकार के लिए काम करेंगे

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

समस्या है,: आप का उपयोग करने के स्पष्ट करने के लिए जो get की जरूरत इनपुट के रूप में।दुर्भाग्य से, भार के 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 के लिए टेम्पलेट, इसलिए आपको इसे मैन्युअल रूप से निर्दिष्ट करना होगा। फ़ंक्शन पॉइंटर को सही प्रकार पर कास्ट करना कंपाइलर को बताता है, "अरे, कृपया अधिभार का उपयोग करें जहां getconst& लेता है और const& देता है!"

लेकिन कम से कम हम मानक पुस्तकालय घटक (yay) का उपयोग कर रहे हैं?

और लाइनों की संख्या के मामले में, यह कोई अन्य विकल्प से भी बदतर है: http://ideone.com/6dfzxz

+1

क्या कोई भी किसी भी सुधार के बारे में सोच सकता है? इस तरह 'std :: get' का उपयोग करने में सक्षम होना बहुत अच्छा होगा। ... वास्तव में मुझे शायद 'reinterperet_cast &)> (std :: <0> प्राप्त करें)' का उपयोग करना चाहिए, लेकिन यह और भी बदतर लगता है ... – NHDaly

+0

मुझे लगता है कि यह एक "लैम्ब्डा" के अंदर लिपटे फ़ंक्शन के साथ "हार्ड" कास्ट को प्रतिस्थापित करना संभव है जिसके लिए कोई तर्क निर्दिष्ट कर सकता है –

3

इस बारे में कैसे?

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

समझने और डीबग करने के लिए सरल।

+0

@ kotlinski: धन्यवाद, लेकिन यह एक आम समाधान है। यदि संभव हो, तो मैं बिना किसी लूप के एक-चरण समाधान ढूंढना चाहता हूं। – justik

+1

आपने कुछ उपयोगकर्ता के अनुकूल होने के लिए कहा, तो यह कुछ सी ++ अत्याचार के साथ उत्तर पोस्ट करने के लिए भ्रामक होगा :) –

+0

+1: इस मामले में सबसे सरल। यदि वे सरल बनाते हैं तो लूप से बचें क्यों? – stefaanv

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

+2

क्या आपके कस्टम फ़ंक्शन के बजाय [std :: <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)); 

(गैर सी ++ 11 कोड के लिए boost::bind द्वारा std::bind बदलें)

10

देख frerich के या के लिए सी ++ 03 kotlinski का जवाब। लैम्ब्डा साथ

सी ++ 11 समाधान:

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

ओह, मैंने "नो लैम्ब्डा" की आवश्यकता नहीं देखी, लेकिन जब यह सीधा और भाषा का हिस्सा क्यों है? – stefaanv

+0

मुझे विश्वास है कि यह सी ++ भाषा का हिस्सा नहीं है, जो यहां के अधिकांश लोग वास्तव में उपयोग कर सकते हैं (या तो कंपाइलर सीमाओं के कारण या कार्यस्थल द्वारा कुछ आवश्यकताओं के कारण)। –

संबंधित मुद्दे