2009-03-11 24 views
16

मैं अगले कोड है:std :: प्रतिलिपि एसटीडी :: एसटीडी के लिए अदालत :: जोड़ी

#include <iostream> 
#include <algorithm> 
#include <map> 
#include <iterator> 

//namespace std 
//{ 

std::ostream& operator << (std::ostream& out, 
       const std::pair< size_t, size_t >& rhs) 
{ 
    out << rhs.first << ", " << rhs.second; 
    return out; 
} 
//} 

int main() 
{ 

    std::map < size_t, size_t > some_map; 

    // fill some_map with random values 
    for (size_t i = 0; i < 10; ++i) 
    { 
     some_map[ rand() % 10 ] = rand() % 100; 
    } 

    // now I want to output this map 
    std::copy( 
     some_map.begin(), 
     some_map.end(), 
     std::ostream_iterator< 
       std::pair< size_t, size_t > >(std::cout, "\n")); 

    return 0; 
} 

इस कोड को मैं सिर्फ उत्पादन धारा को नक्शे की प्रतिलिपि चाहते हैं। ऐसा करने के लिए मुझे ऑपरेटर को परिभाषित करने की आवश्यकता है < < (..) - ठीक है। लेकिन नियमों के अनुसार नियम संकलक मेरे ऑपरेटर < <() नहीं ढूंढ सकते हैं।
क्योंकि std :: cout, std :: pair और std :: प्रतिलिपि जो मेरे ऑपरेटर < < कहा जाता है - सभी नामस्थान std से।

त्वरित समाधान - मेरे नामक < < को std नेमस्पेस में जोड़ें - लेकिन यह बदसूरत, imho है।

इस समस्या के लिए आपको क्या समाधान या समाधान पता है?

+0

बीटीडब्ल्यू, एक एसटीएल एल्गोरिदम है जो पहले फॉर-लूप, http://www.sgi.com/tech/stl/generate.html को पूरा करेगा, फिर यदि आपको वास्तव में लगता है कि यादृच्छिक मानों को यादृच्छिक स्थानों को असाइन करना आवश्यक है , http://www.sgi.com/tech/stl/random_shuffle.html। – paxos1977

उत्तर

13

मैंने इस समस्या को हल करने के लिए एक नया सुरुचिपूर्ण तरीका स्थापित किया है।
मैं जब उत्तर पढ़ कई ब्याज विचारों मिल गया है:

  • रैप इटरेटर, के लिए एसटीडी :: स्ट्रिंग को बदलने std :: जोड़ी;
  • लपेटें std :: जोड़ी, ऑपरेटर को अधिभारित करने का अवसर < < (...);
  • प्रिंटिंग फ़ैक्टर के साथ सामान्य std :: for_each का उपयोग करें;
  • बूस्ट :: labda के साथ std :: for_each का उपयोग करें - std :: pair <> :: पहले और std :: pair <> :: दूसरे सदस्यों तक पहुंच को छोड़कर अच्छा लग रहा है;

मुझे लगता है कि मैं भविष्य में अन्य सभी समस्याओं को हल करने के लिए इन सभी विचारों का उपयोग करूंगा।
लेकिन इस मामले के लिए मैंने यह समझ लिया है कि मैं अपने bproblem को "नक्शा के डेटा को तारों में बदलने और उन्हें आउटपुट स्ट्रीम में लिखने" के रूप में बना सकता हूं, इसके बजाय "नक्शा डेटा को आउटपुट स्ट्रीम में कॉपी करें"। मेरा समाधान इस तरह दिखता है:

namespace 
{ 
std::string toString(const std::pair< size_t, size_t >& data) 
{ 
    std::ostringstream str; 
    str << data.first << ", " << data.second; 
    return str.str(); 
} 
} // namespace anonymous 

std::transform( 
    some_map.begin(), 
    some_map.end(), 
    std::ostream_iterator<std::string>(std::cout, "\n"), 
    toString); 

मुझे लगता है कि यह विधि दूसरों की तुलना में सबसे छोटी और अभिव्यक्तिपूर्ण है।

+0

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

16

std::pair को हल करने का कोई मानक तरीका नहीं है, ठीक है, आप इसे मुद्रित करना चाहते हैं, तो अगले व्यक्ति को यह तरीका अलग-अलग तरीके से अलग है। कस्टम फिक्क्टर या लैम्ब्डा फ़ंक्शन के लिए यह एक अच्छा उपयोग केस है। फिर आप कार्य करने के लिए std::for_each पर तर्क के रूप में इसे पास कर सकते हैं।

typedef std::map<size_t, size_t> MyMap; 

template <class T> 
struct PrintMyMap : public std::unary_function<T, void> 
{ 
    std::ostream& os; 
    PrintMyMap(std::ostream& strm) : os(strm) {} 

    void operator()(const T& elem) const 
    { 
     os << elem.first << ", " << elem.second << "\n"; 
    } 
} 

अपने कोड से functor कॉल करने के लिए:

std::for_each(some_map.begin(), 
       some_map.end(), 
       PrintMyMap<MyMap::value_type>(std::cout)); 
2

[मैं नहीं बल्कि इस जवाब को हटाना चाहते हैं, लेकिन मैं इस मामले में कोई चर्चा दिलचस्प पाता है अब के लिए इसे छोड़ देंगे।]

चूंकि यह std लाइब्रेरी का उचित विस्तार है, इसलिए मैं इसे केवल std नेमस्पेस में रखूंगा, खासकर यदि यह एक बार की बात है। आप लिंकर त्रुटियों को उत्पन्न करने से रोकने के लिए इसे स्थैतिक घोषित कर सकते हैं, किसी और को वही चीज़ करना चाहिए।

एक अन्य समाधान जो मन में आता std :: जोड़ी के लिए एक आवरण बनाने के लिए है:

template<class A, class B> 
struct pairWrapper { 
    const std::pair<A,B> & x; 
    pairWrapper(const std::pair<A,B> & x) : x(x) {} 
} 

template<class A,class B> 
std::ostream & operator<<(std::ostream & stream, const pairWrapper<A,B> & pw) { ... } 
+0

+1, बहुत अच्छा - कनवर्टर कन्स्ट्रक्टर स्वचालित रूप से एक जोड़ी को एक जोड़ी में बदल देगा जब आवश्यक हो। लेकिन कृपया अपने टेम्पलेट ऑपरेटर <<() में ओस्ट्रीम और पैरामीटर जोड़ें। –

+0

अच्छा, धन्यवाद। – bayda

+0

गलत, अस्वीकृत। नेमस्पेस std संकलक-प्रदान की गई कक्षाओं, टेम्पलेट्स और कार्यों के लिए है। आप अधिभार नहीं जोड़ सकते हैं। – MSalters

10

मैं सिर्फ करते रहे कि std :: नाम स्थान के लिए चीजों को जोड़ने के अनुसार अवैध है करना चाहते हैं सी ++ मानक (अनुभाग 17.4.3.1 देखें)।

+0

महत्वपूर्ण टिप्पणी, धन्यवाद। – bayda

+0

एक अपवाद: आप 'std :: swap' के लिए अधिभार जोड़ सकते हैं। –

+0

@ कोनराड क्या आपके पास इसका संदर्भ है? –

5

आप जो चाहते हैं वह एक परिवर्तनीय इटरेटर है। इस तरह के इटरेटर एक और इटरेटर को लपेटता है, आगे ऑपरेटर ++ और ऑपरेटर == जैसी सभी पोजिशनिंग विधियों, लेकिन ऑपरेटर * और ऑपरेटर-> को फिर से परिभाषित करता है।

त्वरित स्केच:

template <typename ITER> 
struct transformingIterator : private ITER { 
    transformingIterator(ITER const& base) : ITER(base) {} 
    transformingIterator& operator++() { ITER::operator++(); return *this; } 
    std::string operator*() const 
    { 
     ITER::value_type const& v = ITER::operator*(); 
     return "[" + v->first +", " + v->second + "]"; 
    } 
... 
+0

धन्यवाद। इटरेटर रैपर बनाने का अच्छा विचार, इस विचार को सामान्यीकृत किया जा सकता है और अन्य समस्याओं को हल करने के लिए उपयोग किया जा सकता है। – bayda

+0

यदि आप कुछ सामान्य चाहते हैं, तो एक स्पष्ट कदम एक उचित बढ़ावा :: फ़ंक्शन में परिवर्तन को संग्रहीत करना है। आप ' डी को नए value_type के लिए एक अतिरिक्त टेम्पलेट पैरामीटर की आवश्यकता है। – MSalters

2

बूस्ट लैम्ब्डा का उपयोग करके आप कुछ इस तरह की कोशिश कर सकते। मेरे पास बूस्ट लैम्ब्डा का संस्करण है, यह वास्तव में काम नहीं करता है, मैं बाद में परीक्षण और ठीक कर दूंगा।

#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 

using namespace boost::lambda; 

std::for_each(some_map.begin(), some_map.end(), 
       std::cout << bind(&std::map<size_t,size_t>::value_type::first, _1) 
         << "," 
         << bind(&std::map<size_t,size_t>::value_type::second, _1)); 
4

बस किसी और के लिए गुजर, लेकिन यह मेरे लिए काम किया है, तो यह कर सकते हैं (कट संस्करण):

template<typename First, typename Second> 
struct first_of { 
    First& operator()(std::pair<First, Second>& v) const { 
     return v.first; 
    } 
}; 

उपयोग मामले को देखते हुए:

transform (v.begin(), v.end(), 
      ostream_iterator<int>(cout, "\n"), first_of<int, string>()); 
0
for_each(some_map.begin(), some_map.end(), [](std::map < size_t, size_t >::value_type &ite){ 
      cout<<ite.first<<" "<<ite.second<<endl; 

}); 

- - यह सी ++ 11

1
for (const auto& your_pair : your_container) 
     your_stream << "[" << your_pair.first << "," << your_pair.second << "]" << endl; 

अधिक सरल और सार्वभौमिक के साथ ठीक है!

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