आप कौन से C ++ मानक पुस्तकालय आवरण कार्यों का उपयोग करते हैं?


81

आज सुबह पूछे गए इस सवाल ने मुझे आश्चर्यचकित कर दिया कि आपको कौन-सी विशेषताएँ लगती हैं जो C ++ स्टैण्डर्ड लाइब्रेरी से गायब हैं, और आप कैसे रैपर फ़ंक्शंस के साथ अंतराल को भरने के बारे में गए हैं। उदाहरण के लिए, मेरी अपनी उपयोगिता पुस्तकालय में वेक्टर परिशिष्ट के लिए यह कार्य है:

template <class T>
std::vector<T> & operator += ( std::vector<T> & v1,
                               const std::vector <T> & v2 ) {
    v1.insert( v1.end(), v2.begin(), v2.end() );
    return v1;
}

और यह किसी भी प्रकार के समाशोधन (अधिक या कम) के लिए - विशेष रूप से std :: stack जैसी चीजों के लिए उपयोगी है:

template <class C>
void Clear( C & c ) {
    c = C();
}

मेरे पास कुछ और हैं, लेकिन मुझे इसमें दिलचस्पी है कि आप किन चीजों का उपयोग करते हैं? कृपया आवरण कार्यों के उत्तर सीमित करें - अर्थात कोड की एक जोड़ी से अधिक नहीं।


9
क्या यह गिना जाता है कि मैंने रेंज के बजाय पूरे कंटेनरों पर कार्य करने के लिए अधिकांश एसटीएल एल्गोरिथ्म को लपेट दिया, सिर्फ इसलिए कि पुनरावृत्तियों के साथ खिलवाड़ करना सिर्फ इतनी आम गलती है :)?
मैथ्यू एम।

2
@ बिली वास्तव में, सीडब्ल्यू वास्तव में व्यक्तिपरक प्रश्न पूछने के लिए एक बहाना नहीं है। मैं शीर्षक बदलूंगा, जिससे लोगों को खुश रहना चाहिए।

4
@kts: चूंकि वेक्टर :: इंसर्ट को रैंडम-एक्सेस iterators दिया गया है, एक अच्छा कार्यान्वयन कंपाइल-टाइम डिस्पैच का उपयोग स्वयं करने के लिए करेगा।

4
क्या c.swap(C())कंटेनर खाली करने के लिए लिखना बेहतर नहीं है ?
अलेक्जेंड्रे सी।

5
@Alexandre: यह अनुमति नहीं है: यह एक गैर-कॉस्ट रेफरी के लिए एक अस्थायी बांधता है। सी ()। स्वैप (सी) काम करेगा।

जवाबों:


37

बढ़ावा :: सरणी

शामिल हैं (कंटेनर, वैल) (काफी सरल, लेकिन सुविधाजनक) है।

template<typename C, typename T>
bool contains(const C& container, const T& val) {
   return std::find(std::begin(container), std::end(container), val) != std::end(container);
}

remove_unstable (शुरू, अंत, मूल्य)

एसटीडी का एक तेज संस्करण :: इस अपवाद के साथ हटा दें कि यह शेष वस्तुओं के आदेश को संरक्षित नहीं करता है।

template <typename T> 
T remove_unstable(T start, T stop, const typename T::value_type& val){  
    while(start != stop) {      
        if (*start == val) {            
            --stop;             
            ::std::iter_swap(start, stop);      
        } else {            
            ++start;        
        }   
    }   
    return stop; 
}

(फली प्रकारों (इंट, फ्लोट आदि) के वेक्टर के मामले में और लगभग सभी वस्तुओं को हटा दिया जाता है, std :: remove तेज हो सकता है)।


4
क्या कोई और सोचता है कि तीसरे टेम्पलेट ( bool sorted=false) और एक विशेषज्ञता की आवश्यकता होती है जब इसके बजाय sorted==trueकॉल binary_searchकरना है find?
KitsuneYMG

6
@kts: जब आप जानते हैं कि कंटेनर सॉर्ट किया गया है, तो सीधे बाइनरी_सर्च को कॉल करें ।

2
बढ़ावा :: सरणी STL समतुल्य सबसे हाल ही में संकलक (यहां तक ​​कि कोडवर्ड) पर tr1 नामस्थान में उपलब्ध है: std :: tr1 :: array <>
Klem

36

अक्सर मैं वेक्टर का उपयोग किसी विशेष क्रम में वस्तुओं के एक सेट के रूप में करता हूं (और, जाहिर है, जब मुझे तेज की आवश्यकता नहीं होती है, तो यह तत्व-इन-द-सेट चेक होता है)। इन मामलों में, कॉलिंग इरेज़ () समय की बर्बादी है क्योंकि यह तत्वों को फिर से व्यवस्थित करेगा और मुझे ऑर्डर की परवाह नहीं है। जब नीचे ओ (1) फ़ंक्शन काम में आता है - तो जिस तत्व को आप हटाना चाहते हैं उसकी स्थिति में अंतिम तत्व को स्थानांतरित करें:

template<typename T>
void erase_unordered(std::vector<T>& v, size_t index)
{
    v[index] = v.back();
    v.pop_back();
}

अच्छा था। ऐसा करने के बारे में नहीं सोचा था .. :) वहाँ एक 'थैला' आवरण (ढेर और कतार के समान) होना चाहिए जो इन ऑप्स को गति देता है जब आदेश महत्वपूर्ण नहीं होता है।
मैके

12
और C ++ 0x में, v[index] = st::move(v.back()); v.pop_back();जितना हो सके उतना कुशल है।
GManNickG

@ मैथ्यू: उन पर टाइम स्टैम्प देखो। : PI ने एक दो घंटे बाद देखा, अनुमति के संपादन के समय से बहुत दूर।
GMANNICKG

@ मन: क्या आप इस बारे में निश्चित हैं? मुझे लगता है जैसे v.pop_back () अनिर्धारित व्यवहार के परिणामस्वरूप हो सकता है क्योंकि विध्वंसक कहा जाएगा।
विक्टर सेहर

1
@Viktor: हटो-शब्दार्थ का अर्थ यह नहीं है कि "मैं आपके संसाधन लेता हूँ और वह ऐसा है", उनका अर्थ है "मैं आपके संसाधन लेता हूँ और आपको बिना संसाधन के राज्य में रखता हूँ।" दूसरे शब्दों में, आपके कदम शब्दार्थ को सुनिश्चित करने की आवश्यकता है कि वस्तु सुरक्षित रूप से नष्ट हो सकती है; करने के लिए बहुत आसान है, बस इशारा करने के लिए संकेत सेट।
GManNickG

26
template < class T >
class temp_value {
    public :
        temp_value(T& var) : _var(var), _original(var) {}
        ~temp_value()        { _var = _original; }
    private :
        T&  _var;
        T   _original;
        temp_value(const temp_value&);
        temp_value& operator=(const temp_value&);
};

ठीक है, क्योंकि ऐसा लगता है कि यह उतना आसान नहीं है जितना मैंने सोचा था, यहाँ एक स्पष्टीकरण है:
इसके निर्माता में temp_valueएक चर के संदर्भ और चर के मूल मूल्य की एक प्रति संग्रहीत है। इसके विध्वंसक में यह संदर्भित चर को उसके मूल मान में पुनर्स्थापित करता है। इसलिए, कोई फर्क नहीं पड़ता कि आपने निर्माण और विनाश के बीच चर के लिए क्या किया है, यह तब रीसेट हो जाएगा जब temp_valueऑब्जेक्ट गुंजाइश से बाहर हो जाता है।
इसे इस तरह उपयोग करें:

void f(some_type& var)
{
  temp_value<some_type> restorer(var); // remembers var's value

  // change var as you like
  g(var);

  // upon destruction restorer will restore var to its original value
}

यहाँ एक और तरीका है जो स्कोप-गार्ड ट्रिक का उपयोग करता है:

namespace detail
{
    // use scope-guard trick
    class restorer_base
    {
    public:
        // call to flag the value shouldn't
        // be restored at destruction
        void dismiss(void) const
        {
            mDismissed = true;
        }

    protected:
        // creation
        restorer_base(void) :
        mDismissed(false) 
        {}

        restorer_base(const restorer_base& pOther) :
        mDismissed(pOther.is_dismissed())
        {
            // take "ownership"
            pOther.dismiss();
        }

        ~restorer_base(void) {} // non-virtual

        // query
        bool is_dismissed(void) const
        {
            return mDismissed;
        }

    private:
        // not copy-assignable, copy-constructibility is ok
        restorer_base& operator=(const restorer_base&);

        mutable bool mDismissed;
    };

    // generic single-value restorer, could be made 
    // variadic to store and restore several variables
    template <typename T>
    class restorer_holder : public restorer_base
    {
    public:
        restorer_holder(T& pX) :
        mX(pX),
        mValue(pX)
        {}

        ~restorer_holder(void)
        {
            if (!is_dismissed())
                mX = mValue;
        }

    private:
        // not copy-assignable, copy-constructibility is ok
        restorer_holder& operator=(const restorer_holder&);

        T& mX;
        T mValue;
    };
}

// store references to generated holders
typedef const detail::restorer_base& restorer;

// generator (could also be made variadic)
template <typename T>
detail::restorer_holder<T> store(T& pX)
{
    return detail::restorer_holder<T>(pX);
}

यह थोड़ा अधिक बॉयलर-प्लेट कोड है, लेकिन एक क्लीनर उपयोग की अनुमति देता है:

#include <iostream>

template <typename T>
void print(const T& pX)
{
    std::cout << pX << std::endl;
}

void foo(void)
{
    double d = 10.0;
    double e = 12.0;
    print(d); print(e);

    {
        restorer f = store(d);
        restorer g = store(e);

        d = -5.0;
        e = 3.1337;
        print(d); print(e);

        g.dismiss();
    }

    print(d); print(e);
}

int main(void)
{
    foo();

    int i = 5;
    print(i);

    {
        restorer r = store(i);

        i *= 123;
        print(i);
    }

    print(i);
}

यह एक कक्षा में उपयोग किए जाने की अपनी क्षमता को हटा देता है, हालांकि।


यहां एक ही प्रभाव प्राप्त करने का तीसरा तरीका है (जो संभावित रूप से विनाशकों को फेंकने की समस्याओं से ग्रस्त नहीं है):

कार्यान्वयन:

//none -- it is built into the language

उपयोग:

#include <iostream>

template <typename T>
void print(const T& pX)
{
    std::cout << pX << std::endl;
}

void foo(void)
{
    double d = 10.0;
    double e = 12.0;
    print(d); print(e);

    {
        double f(d);
        double g(e);

        f = -5.0;
        g = 3.1337;
        print(f); print(g);

        e = std::move(g);
    }

    print(d); print(e);
}

int main(void)
{
    foo();

    int i = 5;
    print(i);

    {
        int r(i);

        r *= 123;
        print(r);
    }

    print(i);
}

1
@ बिली: यह बाद में, स्वचालित रूप से मान को पुनर्स्थापित करने के लिए है। (और घाटी ctor से समाप्त किया जाना चाहिए।)

क्षमा करें, मैं अभी भी खो रहा हूं (मैं C ++ में नया हूं), क्या कोई इसे ठीक से गूंगा करने में सक्षम है?
ड्रीमलैक्स

1
@dreamlax: मैंने कुछ वर्णनात्मक पाठ जोड़कर इसका उत्तर दिया। क्या अब यह समझ में आता है या मुझे विवरण में गहराई से जाना चाहिए?
sbi

1
ओह, दूसरा बहुत सुंदर है।
jalf

1
हम्म क्या है इसके लिए एक वास्तविक जीवन का उपयोग मामला?
पॉलम

22

वास्तव में एक आवरण नहीं है, लेकिन कुख्यात गायब है copy_if। से यहाँ

template<typename In, typename Out, typename Pred>
Out copy_if(In first, In last, Out res, Pred Pr)
{
    while (first != last) {
        if (Pr(*first)) {
            *res++ = *first;
        }
        ++first;
    }
    return res;
}

2
इस सवाल का जवाब नहीं, stdlib के लिए एक आवरण नहीं।

10
@ रॉजर पटे, हां मुझे पता है, इसीलिए इसका उत्तर "वास्तव में एक आवरण नहीं, लेकिन ...." शब्दों से शुरू होता है।
ग्लेन

1
@ रेंजर कार्यान्वयन विस्तार। यदि आप वास्तव में चाहते हैं तो आप इसे लागू कर सकते हैं remove_copy_if()। : पी
विल्हेमटेल २१'१०

18
template< typename T, std::size_t sz >
inline T* begin(T (&array)[sz]) {return array;}

template< typename T, std::size_t sz >
inline T* end  (T (&array)[sz]) {return array + sz;}

2
मेरे पास भी ये हैं। :) +1 यह किस लायक है, इसके लिए आपको केवल दो की जरूरत है (कॉन्स्ट संस्करण को खोदें)। जब ऐरे कांस्ट Tहोगा , होगा const Uऔर आपको इच्छित फंक्शन मिलेगा।
GManNickG

@ मन: जीसीसी के कुछ संस्करण थे जो केवल गैर constसंस्करणों के साथ कुछ कोड संकलित नहीं करेंगे , इसीलिए constसंस्करण हैं। चूँकि वह उस विशेष जीसीसी संस्करण का बग हो सकता है, मैं उन्हें हटा दूंगा।
sbi

1
@ मारकस: ये बूस्ट.रेंज से काफी पुराने हैं। :)
sbi

4
@ रेंजर: यह मानक लीब के साथ उपयोग किए जाने के लिए सरणियों को लपेटता है। तुम वहाँ जाओ। :)
sbi

2
@Stacked, @sbe: एरे को कभी भी मूल्य से पारित नहीं किया जाता है, चाहे कोई भी हो या नहीं &&सरणी की लंबाई के प्रकार कटौती वहाँ सक्षम बनाना है।
मकारसे

12

कभी-कभी मुझे लगता है कि मैं में हूँ begin()और end()नरक। मैं कुछ कार्य करना चाहता हूँ जैसे:

template<typename T>
void sort(T& x)
{
    std::sort(x.begin(), x.end());
}

और के लिए इसी तरह के अन्य लोगों को std::find, std::for_each, और मूल रूप से सभी एसटीएल एल्गोरिदम।

मुझे लगता है कि sort(x)पढ़ने / समझने की तुलना में बहुत तेज है sort(x.begin(), x.end())


1
संकेत; boostsort (बूस्ट :: स्टार्ट (x), बूस्ट: एंड (x)) का उपयोग करें;, इसके बजाय, और आप ऐरे को सॉवेल करने में सक्षम हैं।
विक्टर सेहर

4
Boost.Range v2 में पूरे मानक पुस्तकालय के लिए इस तरह के एडेप्टर हैं।
इलडार्जन

9

मैं इस एक का उपयोग लगभग नहीं करता, लेकिन यह एक प्रधान हुआ करता था:

template<typename T>
std::string make_string(const T& data) {
    std::ostringstream stream;
    stream << data;
    return stream.str();
}

जितना मैं उन्हें याद रखूंगा, उससे ज्यादा अपडेट करेंगे। : पी


3
Hehe - के लिए एक शॉर्टकट की तरह boost::lexical_cast<t, t>
बिली ओनेल

1
हाँ, यह एक बहुत अच्छा है अगर आप एक परियोजना में बढ़ावा नहीं खींचना चाहते हैं
स्टीव

11
@ बिलियोनियल: यही कारण है कि मैं अब इसका इस्तेमाल नहीं करता। @Steve: यही कारण है कि मैं अभी भी इसका उपयोग करता हूं।
जॉन प्यार्डी

यह एक char*या एक पर कॉल करने के लिए अनावश्यक रूप से महंगा होगा std::string। शायद एक खाका विशेषज्ञता क्रम में है?
विल्हेमटेल

अगर मुझे सही से याद है, तो boost::lexical_castइस तरह की विशेषज्ञता और त्रुटि जांच का एक समूह है। हालांकि, विषम संख्या को कठोर करने के लिए, यह ठीक काम करता है।
जॉन पूर्डी

9

हर उपकरण टूलबॉक्स में उपयोगिता फ़ंक्शन निश्चित रूप से है copy_if। हालांकि वास्तव में एक आवरण नहीं।

एक और सहायक मैं आमतौर पर उपयोग करता हूं deleter, एक फ़नकार जिसका उपयोग मैं std::for_eachकंटेनर में सभी पॉइंटर्स को हटाने के लिए करता हूं ।

[संपादित करें] मेरे "sth.h" के माध्यम से खुदाई मैंने भी पाया vector<wstring> StringSplit(wstring const&, wchar_t);


डिलेटर फंक्शनलर्स के लिए +1। मेरा डिलेटर फ़न्क्टर अधिकांश कंटेनरों के साथ अच्छी तरह से काम करता है, हालाँकि मैं इसे std :: मैप के साथ काम करने के लिए इधर-उधर खेल रहा हूँ, जहाँ या तो कुंजी या मान एक पॉइंटर है। मैंने समस्या को हल करने के लिए प्रकार के लक्षणों का उपयोग करने की कोशिश की, लेकिन समय की कमी के कारण वास्तव में बहुत दूर नहीं हुआ। क्या आपने इस मुद्दे को हल किया है या आप इसे एक मुद्दा मानते हैं?
ग्लेन

2
@ मैथ्यू एम। हम सभी को बढ़ावा नहीं दे सकता, दुर्भाग्य से।
ग्लेन

@ गैलन: स्मार्ट पॉइंटर्स का उपयोग करके इन सभी परेशानियों को हल किया जा सकता है, अधिमानतः (लेकिन जरूरी नहीं) को बढ़ावा देने से। एक महत्वपूर्ण दुष्प्रभाव के रूप में, गतिशील रूप से आवंटित वस्तुओं के लिए संकेत के साथ कंटेनर अचानक अपवाद सुरक्षित हो जाते हैं, भी।
sbi

@Glen, यहाँ उन परियोजनाओं के लिए है जो Boost या TR1 सहित, STD के अलावा और कोई लाइब्रेरी नहीं निर्धारित करती हैं।
गेहूं

7
@ कॉर्पोरेट मूर्खता के दुर्भाग्यपूर्ण शिकार: इन-हाउस लाइब्रेरी के लिए एक अपवाद प्राप्त करें, फिर बूस्ट के उपयोगी भागों को इन-हाउस लाइब्रेरी में आयात करें। राजनीति में भी सभी समस्याओं को दूसरे स्तर के अप्रत्यक्ष रूप से हल किया जा सकता है।
MSalters

9

मेरे पास एक हेडर है जो निम्नलिखित को "उपयोग" नामस्थान में रखता है:

// does a string contain another string
inline bool contains(const std::string &s1, const std::string &s2) {
    return s1.find(s2) != std::string::npos;
}

// remove trailing whitespace
inline std::string &rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// remove leading whitespace
inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// remove whitespace from both ends
inline std::string &trim(std::string &s) {
    return ltrim(rtrim(s));
}

// split a string based on a delimeter and return the result (you pass an existing vector for the results)
inline std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

// same as above, but returns a vector for you
inline std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

// does a string end with another string
inline bool endswith(const std::string &s, const std::string &ending) {
    return ending.length() <= s.length() && s.substr(s.length() - ending.length()) == ending;
}

// does a string begin with another string  
inline bool beginswith(const std::string &s, const std::string &start) {
    return s.compare(0, start.length(), start) == 0;
}

2
यह split()किसी भी त्रुटि को निगलता है std::getline(), चुपचाप एक वेक्टर को लौटाना जो बहुत कम है।
sbi

बेशक, आपको size()अपने तार को पुनः प्राप्त करने से पहले परिणाम की जांच करनी चाहिए ।
इवान टे्रन

और मुझे कैसे पता चलेगा कि परिणाम में कितने तार होने चाहिए?
sbi

2
@ एसएसबी: आपकी टिप्पणी ने मेरी रुचि को बढ़ा दिया है कि वास्तव में क्या गलत हो सकता है (स्ट्रिंग से अलग बस पाने के लिए पर्याप्त टोकन नहीं है) stringstream/ getlineलूप के साथ। मैंने इसके बारे में एक सवाल यहाँ रखा है: stackoverflow.com/questions/2562906/…
इवान टेरान

2
@ इवान: मैं सही खड़ा हूं। मेरी टिप्पणी stackoverflow.com/2563542#2563542 पर देखें । माफ़ करना।
sbi

8

कुख्यात लापता eraseएल्गोरिथ्म:

  template <
    class Container,
    class Value
    >
  void erase(Container& ioContainer, Value const& iValue)
  {
    ioContainer.erase(
      std::remove(ioContainer.begin(),
                  ioContainer.end(),
                  iValue),
       ioContainer.end());
  } // erase

  template <
    class Container,
    class Pred
    >
  void erase_if(Container& ioContainer, Pred iPred)
  {
    ioContainer.erase(
      std::remove_if(ioContainer.begin(),
                     ioContainer.end(),
                     iPred),
       ioContainer.end());
  } // erase_if

+1, मेरा सटीक समकक्ष पोस्ट करने वाला था। कम से कम मैंने इसे नाम दिया है remove_erase (...)
विक्टर सेहर

2
इसके साथ एकमात्र समस्या यह है कि यह STL में अपेक्षित अर्थ-मिटाए गए मुहावरे को तोड़ देता है। आपको किसी भी एल्गोरिथ्म के साथ मिटाने-हटाने वाले मुहावरे की आवश्यकता है जो कि शब्दार्थ को हटा दें - न कि सिर्फ std::remove। उदाहरण के लिए, std::unique
बिली ओनली

खैर, मेरे पास इसके लिए अधिकांश एसटीएल एल्गोरिदम के कंटेनर अनुकूलन हैं :) लेकिन यह वह है जिसका मैं सबसे अधिक उपयोग करता हूं, आमतौर पर अगर मैं विशिष्टता चाहता हूं तो मैं setशुरू करने के लिए एक का उपयोग करता हूं ।
Matthieu M.

@ मैथ्यू एम।: बस इसे ध्यान में रखते हुए आप ऐसे लोगों के साथ काम करेंगे जो हर समय एसटीएल के साथ काम करते हैं, जिनके सिर में अलार्म की घंटी बज रही होती है "चेतावनी: याद रखें-पसंद ALGORITHM साथ NOALL TO ERASE !!" । वहाँ वास्तव में इसके साथ कुछ भी गलत नहीं है, लेकिन अगर मुझे कई प्रोग्रामर के बीच अपना कोड साझा करने की आवश्यकता है तो ऐसा कुछ नहीं होगा। बस मेरे 2 सेंट।
बिली ओनेल

1
@ बिली: यही कारण है कि मैंने इसे मिटा दिया और हटा नहीं। इसके अलावा मैं ऐसा कुछ नहीं कर सकता, इसके अलावा उन्हें कोड से परामर्श करने दें। आधुनिक आईडीई के साथ शुक्र है कि परिभाषा सिर्फ एक क्लिक दूर है :)
Matthieu M.

7

अंकुर फूटना

string example = function("<li value='%d'>Buffer at: 0x%08X</li>", 42, &some_obj);
// 'function' is one of the functions below: Format or stringf

लक्ष्य स्प्रिंटफ और इसके ilk के साथ मुसीबत में पड़ने के बिना आउटपुट से फ़ॉर्मेटिंग को डिकूपिंग कर रहा है। यह सुंदर नहीं है, लेकिन यह बहुत उपयोगी है, खासकर यदि आपके कोडिंग दिशानिर्देश iostreams पर प्रतिबंध लगाते हैं।


यहां एक संस्करण है जो नील बटरवर्थ से आवश्यकतानुसार आवंटित किया गया है। [माइक के संस्करण के लिए संशोधन इतिहास देखें, जिसे मैंने शेष दो के सबसेट के रूप में हटा दिया। यह नील के समान है, सिवाय इसके कि हटाए जाने के बजाय वेक्टर का उपयोग करके उत्तरार्द्ध अपवाद-सुरक्षित है []: स्ट्रिंग का ctor आवंटन विफलता के लिए फेंक देगा। माइक भी उसी तकनीक का उपयोग करता है जो बाद में सामने के आकार को निर्धारित करने के लिए दिखाई जाती है। -RP]

string Format( const char * fmt, ... ) {
  const int BUFSIZE = 1024;
  int size = BUFSIZE, rv = -1;
  vector <char> buf;
  do {
    buf.resize( size );
    va_list valist;
    va_start( valist, fmt );
    // if _vsnprintf() returns < 0, the buffer wasn't big enough
    // so increase buffer size and try again
    // NOTE: MSFT's _vsnprintf is different from C99's vsnprintf,
    //       which returns non-negative on truncation
    //       http://msdn.microsoft.com/en-us/library/1kt27hek.aspx
    rv = _vsnprintf( &buf[0], size, fmt, valist );
    va_end( valist );
    size *= 2;
  }
  while( rv < 0 );
  return string( &buf[0] );
}

यहां एक संस्करण है जो रोजर पटे से सामने के आकार की आवश्यकता को निर्धारित करता है । इसके लिए लेखन योग्य std :: स्ट्रिंग्स की आवश्यकता होती है, जो लोकप्रिय कार्यान्वयन द्वारा प्रदान किए जाते हैं, लेकिन C ++ 0x द्वारा स्पष्ट रूप से आवश्यक हैं। [मार्कस के संस्करण के लिए संशोधन इतिहास देखें, जिसे मैंने हटा दिया क्योंकि यह थोड़ा अलग है लेकिन अनिवार्य रूप से नीचे का सबसेट है। -RP]

कार्यान्वयन

void vinsertf(std::string& s, std::string::iterator it,
             char const* fmt, int const chars_needed, va_list args
) {
  using namespace std;
  int err; // local error code
  if (chars_needed < 0) err = errno;
  else {
    string::size_type const off = it - s.begin(); // save iterator offset
    if (it == s.end()) { // append to the end
      s.resize(s.size() + chars_needed + 1); // resize, allow snprintf's null
      it = s.begin() + off; // iterator was invalidated
      err = vsnprintf(&*it, chars_needed + 1, fmt, args);
      s.resize(s.size() - 1); // remove snprintf's null
    }
    else {
      char saved = *it; // save char overwritten by snprintf's null
      s.insert(it, chars_needed, '\0'); // insert needed space
      it = s.begin() + off; // iterator was invalidated
      err = vsnprintf(&*it, chars_needed + 1, fmt, args);
      *(it + chars_needed) = saved; // restore saved char
    }

    if (err >= 0) { // success
      return;
    }
    err = errno;
    it = s.begin() + off; // above resize might have invalidated 'it'
    // (invalidation is unlikely, but allowed)
    s.erase(it, it + chars_needed);
  }
  string what = stringf("vsnprintf: [%d] ", err);
  what += strerror(err);
  throw runtime_error(what);
}

सार्वजनिक इंटरफ़ेस

std::string stringf(char const* fmt, ...) {
  using namespace std;
  string s;
  va_list args;
  va_start(args, fmt);
  int chars_needed = vsnprintf(0, 0, fmt, args);
  va_end(args);
  va_start(args, fmt);
  try {
    vinsertf(s, s.end(), fmt, chars_needed, args);
  }
  catch (...) {
    va_end(args);
    throw;
  }
  va_end(args);
  return s;
}

// these have nearly identical implementations to stringf above:
std::string& appendf(std::string& s, char const* fmt, ...);
std::string& insertf(std::string& s, std::string::iterator it,
                    char const* fmt, ...);

@Neil: से man vsnprintf: "ये काम करता है, वर्णों की संख्या मुद्रित ... या एक नकारात्मक मूल्य वापसी एक आउटपुट त्रुटि तब होती है, तो सिवाय के लिए snprintf()और vsnprintf()है, जो वर्ण होता है कि यदि n असीमित थे मुद्रित किया गया है की संख्या लौट ... "इसलिए डमी कॉल 0 बफर के साथ आवश्यक बफर आकार को मापने के लिए कहता है।
माइक डीसिमोन

@ चेकर्स: आह, बूस्ट। इतनी बड़ी क्षमता कि वे मुझे भी इस्तेमाल नहीं करने देंगे। किसी दिन, उम्मीद है। वैसे भी, बूस्ट काफी बड़ा हो गया है पूरी तरह से अभी तक समझना असंभव है? मैं बस पाने के लिए खुश हूँ boost::spirit
माइक डीमोन

यह वास्तव में विंडोज कोड है - MSDN से "_vsnprintf के लिए, यदि बाइट लिखने के लिए बाइट्स की संख्या बफर से अधिक है, तो काउंट बाइट्स लिखे जाते हैं और -1 को वापस कर दिया जाता है।" लेकिन मैं इसे लिनक्स में पोर्ट करता हूं। मुझे याद नहीं है कि क्या मेरा लिनक्स ऐप वास्तव में इसका उपयोग करता है, या यदि मैंने इसे बड़े बफर आकारों के लिए परीक्षण किया है - तो ऐसा अवश्य करना चाहिए। धन्यवाद।

1
यदि आप वैसे भी विंडोज कोड का उपयोग करते हैं, तो आगे बढ़ें और _vscprintfबफर के आवश्यक आकार को निर्धारित करने के लिए उपयोग करें।
स्मरलिन

6

is_sortedउपयोगिता, एल्गोरिदम की तरह लागू करने से पहले परीक्षण कंटेनरों को includeजो एक क्रमबद्ध प्रवेश की उम्मीद:

  template <
    class FwdIt
  >
  bool is_sorted(FwdIt iBegin, FwdIt iEnd)
  {
    typedef typename std::iterator_traits<FwdIt>::value_type value_type;
    return adjacent_find(iBegin, iEnd, std::greater<value_type>()) == iEnd;
  } // is_sorted

  template <
    class FwdIt,
    class Pred
  >
  bool is_sorted_if(FwdIt iBegin, FwdIt iEnd, Pred iPred)
  {
    if (iBegin == iEnd) return true;
    FwdIt aIt = iBegin;
    for (++aIt; aIt != iEnd; ++iBegin, ++aIt)
    {
      if (!iPred(*iBegin, *aIt)) return false;
    }
    return true;
  } // is_sorted_if

हाँ, मुझे पता है, विधेय को नकारना और विधेय संस्करण का उपयोग करना बेहतर होगा adjacent_find:)


1
जब तक आप केवल एक परीक्षण करते हैं assert(): पी
विल्हेमटेल

आपको हंगेरियन नोटेशन का उपयोग नहीं करना चाहिए।
The_drow

3
@the_drow: इस उपयोगी टिप्पणी के लिए बहुत बहुत धन्यवाद :) मैं इसके बारे में इतना प्रशंसक नहीं हूं, लेकिन यह एक ऐसी आवश्यकता है जहां मैं काम करता हूं ... मैंने तब से आदत को हिला दिया है, मेरी आत्मा की चिंता मत करो;)
मैथ्यू एम।

3

निश्चित रूप से बढ़ावा :: पता


असल में, मैंने ओवरलोडिंग के बारे में बहुत सारी चर्चाएँ सुनी हैं, लेकिन मैंने कभी ऐसा नहीं देखा, किसी ने वास्तव में ऐसा न किया हो (हम्म बिट_ट्रांसफरेंस)।
विक्टर सेहर

@ विक्टर सेहर: ATL :: CComPtr ( msdn.microsoft.com/en-us/library/ezzw7k98(VS.80).aspx ) और _com_ptr_t ( msdn.microsoft.com/en-us/library/417w8b3b(VS.80) ) .aspx ) अच्छे उदाहरण हैं।
शार्प फुट

3
//! \brief Fills reverse_map from map, so that all keys of map 
//         become values of reverse_map and all values become keys. 
//! \note  This presumes that there is a one-to-one mapping in map!
template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 >
inline void build_reverse_map( const std::map<T1,T2,TP1,TA1>& map
                             ,       std::map<T2,T1,TP2,TA2>& reverse_map)
{
    typedef std::map<T1,T2,TP1,TA1>         map_type;
    typedef std::map<T2,T1,TP2,TA2>         r_map_type;
    typedef typename r_map_type::value_type r_value_type;

    for( typename map_type::const_iterator it=map.begin(),
                                          end=map.end(); it!=end; ++it ) {
        const r_value_type v(it->second,it->first);
        const bool was_new = reverse_map.insert(v).second;
        assert(was_new);
    }
}

मैं Boost.Bimapपुस्तकालय का उपयोग करना पसंद करता हूं (या Boost.MultiIndexअधिक जटिल स्थितियों के लिए)
मैथ्यू एम।

1
मुझे नहीं मिला, क्यों मुखर ()?
विक्टर सेहर

@Viktor: यह सुनिश्चित करने के लिए कि इसमें कोई डुप्लिकेट कीज़ नहीं हैं reverse_map। विचार करें map(1 -> "एक"; 2 -> "एक") reverse_mapको एक तत्व मिलेगा ("एक" -> 1)। मुखर उस को पकड़ लेगा। इसे भी देखें:
जीवनी

3
Btw, sbi, एक मुखर () के भीतर साइड इफेक्ट के साथ कोड होने से आप NDEBUG के साथ संकलन करने के बाद आपको बहुत बुरा काटेंगे और मुखर () पूरी तरह से छीन लिए जाते हैं।
sbk

2
जीए, अपडेट के बाद मेरी पहली टिप्पणी वास्तव में बेवकूफ लग रही है, स्टैकओवरफ़्लो # 1 है जब मेरा नाम गुगला रहा है तो मुझे आशा है कि कोई भविष्य के नियोक्ता को यह नहीं दिखता है))
विक्टर सेहर

3

मेरे stl_util.h, क्लासिक्स के कई (डिलेटर फ़ंक्शंस copy_if) को देखते हुए, और यह भी एक (शायद यह भी काफी सामान्य है, लेकिन मैं इसे अब तक दिए गए जवाबों में नहीं देखा) मैप के माध्यम से खोज करने और या तो पाया गया मान वापस करने के लिए या एक डिफ़ॉल्ट, getपायथन में अला dict:

template<typename K, typename V>
inline V search_map(const std::map<K, V>& mapping,
                    const K& key,
                    const V& null_result = V())
   {
   typename std::map<K, V>::const_iterator i = mapping.find(key);
   if(i == mapping.end())
      return null_result;
   return i->second;
   }

डिफ़ॉल्ट का उपयोग करते हुए null_resultकी एक डिफ़ॉल्ट-निर्माण Vमें ज्यादा के व्यवहार के रूप में ही रूप में है std::mapकी operator[], लेकिन जब नक्शा स्थिरांक (मेरे लिए सामान्य) है यह उपयोगी है, या यदि डिफ़ॉल्ट-निर्माण वी उपयोग करने के लिए सही बात नहीं है।


क्या होगा यदि V एक इंट या फ्लोट या कुछ अन्य आदिम है?
उलटा

खाली मान-आरंभीकरण C ++ में बुनियादी प्रकारों के लिए काम करता है। पूर्णांक और फ़्लोट्स के लिए, जो कि डिफ़ॉल्ट null_result 0. को बनाएगा
जैक लॉयड

3

यहाँ मेरे अतिरिक्त-सेट का सेट है, जो एक बूस्टर के ऊपर बनाया गया है। std-algo आवरण जो आपको कुछ कार्यों के लिए आवश्यक हो सकता है। (यह लिखने के लिए तुच्छ है, यह दिलचस्प सामग्री है)

#pragma once


/** @file
    @brief Defines various utility classes/functions for handling ranges/function objects
           in addition to bsRange (which is a ranged version of the \<algorithm\> header)

    Items here uses a STL/boost-style naming due to their 'templatised' nature.

    If template variable is R, anything matching range_concept can be used. 
    If template variable is C, it must be a container object (supporting C::erase())
*/

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/smart_ptr.hpp>

namespace boost
{
struct use_default; 

template<class T>
class iterator_range;

#pragma warning(disable: 4348) // redeclaration of template default parameters (this clashes with fwd-decl in boost/transform_iterator.hpp)
template <
    class UnaryFunction
  , class Iterator
  , class Reference = use_default
  , class Value = use_default
>
class transform_iterator;

template <
    class Iterator
  , class Value = use_default
  , class Category   = use_default
  , class Reference  = use_default
  , class difference = use_default
>
class indirect_iterator;

template<class T>
struct range_iterator;

template <
    class Incrementable
  , class CategoryOrTraversal = use_default
  , class difference = use_default
>
class counting_iterator;

template <class Predicate, class Iterator>
class filter_iterator;

}

namespace orz
{

/// determines if any value that compares equal exists in container
template<class R, class T>
inline bool contains(const R& r, const T& v) 
{
    return std::find(boost::begin(r), boost::end(r), v) != boost::end(r);
}

/// determines if predicate evaluates to true for any value in container
template<class R, class F>
inline bool contains_if(const R& r, const F& f) 
{
    return std::find_if(boost::begin(r), boost::end(r), f) != boost::end(r);
}

/// insert elements in range r at end of container c
template<class R, class C>
inline void insert(C& c, const R& r)
{
    c.insert(c.end(), boost::begin(r), boost::end(r));
}
/// copy elements that match predicate
template<class I, class O, class P>
inline void copy_if(I i, I end, O& o, const P& p)
{
    for (; i != end; ++i) {
        if (p(*i)) {
            *o = *i;
            ++o;
        }
    }
}

/// copy elements that match predicate
template<class R, class O, class P>
inline void copy_if(R& r, O& o, const P& p)
{
    copy_if(boost::begin(r), boost::end(r), o, p);
}

/// erases first element that compare equal
template<class C, class T>
inline bool erase_first(C& c, const T& v) 
{
    typename C::iterator end = boost::end(c);
    typename C::iterator i = std::find(boost::begin(c), end, v);
    return i != c.end() ? c.erase(i), true : false;
}

/// erases first elements that match predicate
template<class C, class F>
inline bool erase_first_if(C& c, const F& f) 
{
    typename C::iterator end = boost::end(c);
    typename C::iterator i = std::find_if(boost::begin(c), end, f);
    return i != end ? c.erase(i), true : false;
}

/// erase all elements (doesn't deallocate memory for std::vector)
template<class C>
inline void erase_all(C& c) 
{
    c.erase(c.begin(), c.end());
}

/// erase all elements that compare equal
template<typename C, typename T>
int erase(C& c, const T& value)
{
    int n = 0;

    for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
        if (*i == value) {
            i = c.erase(i);
            ++n;
        } else {
            ++i;
        }
    }

    return n;
}

/// erase all elements that match predicate
template<typename C, typename F>
int erase_if(C& c, const F& f)
{
    int n = 0;

    for (boost::range_iterator<C>::type i = boost::begin(c); i != boost::end(c);) {
        if (f(*i)) {
            i = c.erase(i);
            ++n;
        } else {
            ++i;
        }
    }

    return n;
}


/// erases all consecutive duplicates from container (sort container first to get all)
template<class C>
inline int erase_duplicates(C& c)
{
    boost::range_iterator<C>::type i = std::unique(c.begin(), c.end());
    typename C::size_type n = std::distance(i, c.end());
    c.erase(i, c.end());
    return n;
}

/// erases all consecutive duplicates, according to predicate, from container (sort container first to get all)
template<class C, class F>
inline int erase_duplicates_if(C& c, const F& f)
{
    boost::range_iterator<C>::type i = std::unique(c.begin(), c.end(), f);
    typename C::size_type n = std::distance(i, c.end());
    c.erase(i, c.end());
    return n;
}

/// fill but for the second value in each pair in range
template<typename R, typename V>
inline void fill_second(R& r, const V& v)
{
    boost::range_iterator<R>::type i(boost::begin(r)), end(boost::end(r));

    for (; i != end; ++i) {
        i->second = v;
    }
}

/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename F>
void for_each2(R1& r1, R2& r2, const F& f)
{
    boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
    boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));

    for(;i != i_end && j != j_end; ++i, ++j) {
        f(*i, *j);
    }    
}

/// applying function to corresponding pair through both ranges, min(r1.size(), r2,size()) applications
template<typename R1, typename R2, typename R3, typename F>
void for_each3(R1& r1, R2& r2, R3& r3, const F& f)
{
    boost::range_iterator<R1>::type i(boost::begin(r1)), i_end(boost::end(r1));
    boost::range_iterator<R2>::type j(boost::begin(r2)), j_end(boost::end(r2));
    boost::range_iterator<R3>::type k(boost::begin(r3)), k_end(boost::end(r3));

    for(;i != i_end && j != j_end && k != k_end; ++i, ++j, ++k) {
        f(*i, *j, *k);
    }    
}


/// applying function to each possible permutation of objects, r1.size() * r2.size() applications
template<class R1, class R2, class F>
void for_each_permutation(R1 & r1, R2& r2, const F& f)
{
    typedef boost::range_iterator<R1>::type R1_iterator;
    typedef boost::range_iterator<R2>::type R2_iterator;

    R1_iterator end_1 = boost::end(r1);
    R2_iterator begin_2 = boost::begin(r2);
    R2_iterator end_2 = boost::end(r2);

    for(R1_iterator i = boost::begin(r1); i != end_1; ++i) {
        for(R2_iterator j = begin_2; j != end_2; ++j) {
            f(*i, *j);
        }
    }
}

template <class R>
inline boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > 
make_indirect_range(R& r)
{
    return boost::iterator_range<boost::indirect_iterator<typename boost::range_iterator<R>::type > > (r);
}

template <class R, class F>
inline boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> > 
make_transform_range(R& r, const F& f)
{
    return boost::iterator_range<boost::transform_iterator<F, typename boost::range_iterator<R>::type> >(
        boost::make_transform_iterator(boost::begin(r), f), 
        boost::make_transform_iterator(boost::end(r), f));
}

template <class T>
inline boost::iterator_range<boost::counting_iterator<T>  >
make_counting_range(T begin, T end)
{
    return boost::iterator_range<boost::counting_iterator<T> >(
        boost::counting_iterator<T>(begin), boost::counting_iterator<T>(end));
}

template <class R, class F>
inline boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >
make_filter_range(R& r, const F& f)
{
    return boost::iterator_range<boost::filter_iterator<F, typename boost::range_iterator<R>::type> >(
        boost::make_filter_iterator(f, boost::begin(r), boost::end(r)),
        boost::make_filter_iterator(f, boost::end(r), boost::end(r)));
}

namespace detail {

template<class T>
T* get_pointer(T& p) {
    return &p;
}

}

/// compare member function/variable equal to value. Create using @ref mem_eq() to avoid specfying types 
template<class P, class V>
struct mem_eq_type
{
    mem_eq_type(const P& p, const V& v) : m_p(p), m_v(v) { }

    template<class T>
    bool operator()(const T& a) const {
        using boost::get_pointer;
        using orz::detail::get_pointer;
        return (get_pointer(a)->*m_p) == m_v;
    }

    P m_p;
    V m_v;
};


template<class P, class V>
mem_eq_type<P,V> mem_eq(const P& p, const V& v) 
{
    return mem_eq_type<P,V>(p, v);
}

/// helper macro to define function objects that compare member variables of a class
#define ORZ_COMPARE_MEMBER(NAME, OP) \
    template <class P> \
    struct NAME##_type \
    { \
        NAME##_type(const P&p) : m_p(p) {} \
        template<class T> \
        bool operator()(const T& a, const T& b) const { \
            return (a.*m_p) OP (b.*m_p); \
        } \
        P m_p; \
    }; \
    template <class P> \
    NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }

#define ORZ_COMPARE_MEMBER_FN(NAME, OP) \
    template <class P> \
    struct NAME##_type \
    { \
        NAME##_type(const P&p) : m_p(p) {} \
        template<class T> \
        bool operator()(const T& a, const T& b) const { \
        return (a.*m_p)() OP (b.*m_p)(); \
    } \
        P m_p; \
    }; \
    template <class P> \
    NAME##_type<P> NAME(const P& p) { return NAME##_type<P>(p); }

/// helper macro to wrap range functions as function objects (value return)
#define ORZ_RANGE_WRAP_VALUE_2(FUNC, RESULT)                              \
    struct FUNC##_                                                \
    {                                                             \
        typedef RESULT result_type;                               \
        template<typename R, typename F>                          \
        inline RESULT operator() (R&  r, const F&  f) const       \
        {                                                         \
            return FUNC(r, f);                                    \
        }                                                         \
    };

/// helper macro to wrap range functions as function objects (void return)
#define ORZ_RANGE_WRAP_VOID_2(FUNC)                                 \
    struct FUNC##_                                                \
    {                                                             \
        typedef void result_type;                                 \
        template<typename R, typename F>                          \
        inline void operator() (R&  r, const F&  f) const         \
        {                                                         \
            FUNC(r, f);                                           \
        }                                                         \
    };

/// helper macro to wrap range functions as function objects (void return, one argument)
#define ORZ_RANGE_WRAP_VOID_1(FUNC)                                 \
    struct FUNC##_                                                \
    {                                                             \
        typedef void result_type;                                 \
        template<typename R>                          \
        inline void operator() (R&  r) const         \
        {                                                         \
            FUNC(r);                                           \
        }                                                         \
    }; 

ORZ_RANGE_WRAP_VOID_2(for_each);
ORZ_RANGE_WRAP_VOID_1(erase_all);
ORZ_RANGE_WRAP_VALUE_2(contains, bool);
ORZ_RANGE_WRAP_VALUE_2(contains_if, bool);
ORZ_COMPARE_MEMBER(mem_equal, ==)
ORZ_COMPARE_MEMBER(mem_not_equal, !=)
ORZ_COMPARE_MEMBER(mem_less, <)
ORZ_COMPARE_MEMBER(mem_greater, >)
ORZ_COMPARE_MEMBER(mem_lessequal, <=)
ORZ_COMPARE_MEMBER(mem_greaterequal, >=)
ORZ_COMPARE_MEMBER_FN(mem_equal_fn, ==)
ORZ_COMPARE_MEMBER_FN(mem_not_equal_fn, !=)
ORZ_COMPARE_MEMBER_FN(mem_less_fn, <)
ORZ_COMPARE_MEMBER_FN(mem_greater_fn, >)
ORZ_COMPARE_MEMBER_FN(mem_lessequal_fn, <=)
ORZ_COMPARE_MEMBER_FN(mem_greaterequal_fn, >=)

#undef ORZ_COMPARE_MEMBER
#undef ORZ_RANGE_WRAP_VALUE_2
#undef ORZ_RANGE_WRAP_VOID_1
#undef ORZ_RANGE_WRAP_VOID_2
}

+1 for_each_permutation (...) , मुख्यतः क्योंकि मैंने एक समान आवरण = लिखा है। लेकिन क्यों मिटाया जाता है_डुप्लिकेट्स (...) एक हस्ताक्षरित इंट वापस?
विक्टर सेहर

हाय विक्टर! मुझे लगता है कि आपने अपनी पिछली नौकरी में for_each_permutation देखा होगा । ;) erase_duplicates मिटाए गए तत्वों की संख्या देता है, जो लॉगिंग और डीबगिंग के लिए उपयोगी है।
मैके

हम्म ने इसे महसूस नहीं किया है कि यह क्या करता है ?) , वैसे भी, मुझे लगता है कि यह क्यों एक पूर्णांक लौटाता है, मुझे नहीं मिला कि पूर्णांक पर हस्ताक्षर क्यों किया गया है (या अधिक विशिष्ट होने के लिए; यह अहस्ताक्षरित क्यों नहीं है )?
विक्टर सेहर

आह। बस मेरी ओर से आलस्य: -प. size_t उपयुक्त प्रकार है।
मैके

3

मुझे कार्टिसियन उत्पाद की आवश्यकता प्रतीत होती है, उदाहरण के लिए {ए, बी}, {1, 2} -> {(ए, 1), (ए, 2), (बी, 1), (बी, 2)}

// OutIt needs to be an iterator to a container of std::pair<Type1, Type2>
template <typename InIt1, typename InIt2, typename OutIt>
OutIt
cartesian_product(InIt1 first1, InIt1 last1, InIt2 first2, InIt2 last2, OutIt out)
{
    for (; first1 != last1; ++first1)
        for (InIt2 it = first2; it != last2; ++it)
            *out++ = std::make_pair(*first1, *it);
    return out;
}

ध्यान दें कि InIt2 एक इनपुट पुनरावृत्ति के बजाय एक अग्रगामी होना चाहिए । इनपुट पुनरावृत्तियां कई पास के लिए उपयुक्त नहीं हैं।

2

मैं उसके नाम से इस तरह के एक एपेंड फ़ंक्शन को कॉल करूंगा और ऑपरेटर-=, ऑपरेटर * = का उपयोग करूंगा और तत्व-वार संचालन के लिए, जैसे:

    template<typename X> inline void operator+= (std::vector<X>& vec1, const X& value)
    {
      std::transform( vec1.begin(), vec1.end(), vec1.begin(), std::bind2nd(std::plus<X>(),value) );
    }

    template<typename X> inline void operator+= (std::vector<X>& vec1, const std::vector<X>& vec2)
    {
      std::transform( vec1.begin(), vec1.end(), vec2.begin(), vec1.begin(), std::plus<X>() );
    }

इससे पहले निहित कुछ अन्य सरल और स्पष्ट रैपर:

    template<typename X> inline void sort_and_unique(std::vector<X> &vec)
    {
        std::sort( vec.begin(), vec.end() );
        vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() );
    }


    template<typename X> inline void clear_vec(std::vector<X> &vec)
    {
        std::vector<X>().swap(vec);
    }


    template<typename X> inline void trim_vec(std::vector<X> &vec, std::size_t new_size)
    {
        if (new_size<vec.size())
            std::vector<X>(vec.begin(),vec.begin() + new_size).swap(vec);
        else
            std::vector<X>(vec).swap(vec);
    }

7
ये ऑपरेटर एक बहुत अच्छा उदाहरण हैं कि ऑपरेटर ओवरलोडिंग शायद ही कभी किया जाना चाहिए। मैंने सोचा vec+=valहोगा , वेक्टर के लिए एक मूल्य जोड़ देगा । (देखें stackoverflow.com/questions/2551775/। ) अब जब मैंने आपका कार्यान्वयन देख लिया है, तो मुझे लगता है कि यह सही अर्थ की व्याख्या +=भी है। मुझे पता नहीं है जो एक सही है या गलत हो सकता है, तो यह शायद बस के रूप में अच्छी तरह से है कि हम की जरूरत नहीं है +=के लिए std::vector
sbi

1
@sbi मैं सहमत हूँ। मुझे operator+()मानक की एक अद्भुत शुरुआती जानकारी याद आ रही है। मुझे आमतौर पर ओ (1) ऑपरेशन की उम्मीद है हर जगह मैं प्लस ऑपरेटर देखता हूं। C ++ ऐसी चीज़े बनाती है जो महंगी या खतरनाक होती हैं, जो अधिक कठिन या कठिन होती हैं, और मुझे यह पसंद है। जावा पर एक नज़र डालें: सबसे खराब कोडिंग गलतियों में से एक प्लस ऑपरेटर का दुरुपयोग है। बेशक, फिर से, सी ++ हमेशा सस्ते और तेज चीजों को आसान नहीं बनाता है, लेकिन हे। अच्छे C ++ प्रोग्रामर बहुत अधिक प्रदर्शन के प्रति जागरूक होते हैं। ;)
विल्हेमटेल

2
मैं आप दोनों से सहमत हूँ जो op+()इसकी अस्पष्टता के कारण बिल्कुल भी परिभाषित नहीं होना चाहिए। लेकिन वैक्टर आमतौर पर (गणितीय) वेक्टर स्थान का हिस्सा होते हैं और दो वैक्टर और स्केलर गुणन को जोड़ने की एक विहित परिभाषा है। अपने तर्क को और आगे ले जाने के लिए: एक doubleसदिश एक सदिश राशि है, इसलिए यदि आप दो doubleचर जोड़ते हैं a+bतो आप एक नया doubleऔर नहीं pairकी तरह एक दो पाने की उम्मीद करेंगे (a,b)। एक स्केलर के साथ गुणा करना भी विहित है, लेकिन दो वैक्टर को गुणा करना नहीं है। इसलिए ओवरलोडिंग को सावधानी से किया जाना चाहिए ..
डेन

1

एक नया आइटम डालें और इसे लौटाएं, सरल चाल शब्दार्थ जैसे push_back(c).swap(value)और संबंधित मामलों के लिए उपयोगी ।

template<class C>
typename C::value_type& push_front(C& container) {
  container.push_front(typename C::value_type());
  return container.front();
}

template<class C>
typename C::value_type& push_back(C& container) {
  container.push_back(typename C::value_type());
  return container.back();
}

template<class C>
typename C::value_type& push_top(C& container) {
  container.push(typename C::value_type());
  return container.top();
}

पॉप और एक आइटम लौटें:

template<class C>
typename C::value_type pop_front(C& container) {
  typename C::value_type copy (container.front());
  container.pop_front();
  return copy;
}

template<class C>
typename C::value_type pop_back(C& container) {
  typename C::value_type copy (container.back());
  container.pop_back();
  return copy;
}

template<class C>
typename C::value_type pop_top(C& container) {
  typename C::value_type copy (container.top());
  container.pop();
  return copy;
}

1

IMO के लिए और अधिक कार्यक्षमता की आवश्यकता है pair:

#ifndef pair_iterator_h_
#define pair_iterator_h_

#include <boost/iterator/transform_iterator.hpp>    
#include <functional>
#include <utility>    

// pair<T1, T2> -> T1
template <typename PairType>
struct PairGetFirst : public std::unary_function<PairType, typename PairType::first_type>
{
    typename typename PairType::first_type& operator()(PairType& arg) const
    {       return arg.first;   }
    const typename PairType::first_type& operator()(const PairType& arg) const
    {       return arg.first;   }
};



// pair<T1, T2> -> T2
template <typename PairType>
struct PairGetSecond : public std::unary_function<PairType, typename PairType::second_type>
{
    typename PairType::second_type& operator()(PairType& arg) const
    {       return arg.second;  }
    const typename PairType::second_type& operator()(const PairType& arg) const
    {       return arg.second;  }
};



// iterator over pair<T1, T2> -> iterator over T1
template <typename Iter>
boost::transform_iterator<PairGetFirst<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_first_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetFirst<typename std::iterator_traits<Iter>::value_type>());
}



// iterator over pair<T1, T2> -> iterator over T2
template <typename Iter>
boost::transform_iterator<PairGetSecond<typename std::iterator_traits<Iter>::value_type>, Iter> 
make_second_iterator(Iter i)
{
    return boost::make_transform_iterator(i, 
        PairGetSecond<typename std::iterator_traits<Iter>::value_type>());
}



// T1 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair1st : public std::unary_function<FirstType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair1st(const SecondType& second_element) : second_(second_element) {}
    result_type operator()(const FirstType& first_element)
    {
        return result_type(first_element, second_);
    }
private:
    SecondType second_;
};



// T2 -> pair<T1, T2>
template <typename FirstType, typename SecondType>
class InsertIntoPair2nd : public std::unary_function<SecondType, std::pair<FirstType, SecondType> >
{
public:
    InsertIntoPair2nd(const FirstType& first_element) : first_(first_element) {}
    result_type operator()(const SecondType& second_element)
    {
        return result_type(first_, second_element);
    }
private:
    FirstType first_;
};

#endif // pair_iterator_h_

1
PairTypeटेम्प्लेट को ऑपरेटर () में स्थानांतरित क्यों नहीं किया जाता है ? इसके अलावा, पहचानकर्ता में डबल-अंडरस्कोर सुरक्षित हैं।
GManNickG

@ गमन - क्योंकि तब आप उपयोग नहीं कर सकते हैं unary_function, जो मुझे अपने कोड में कुछ बिंदु पर चाहिए। डबल-अंडरस्कोर के लिए, मुझे बताने के लिए धन्यवाद - मुझे इसे बदलने की आवश्यकता होगी।
आरएलबोंड

यह गलत तरीके से आश्रित नामों (तर्क_type, result_type) का उपयोग करता है और इसे अस्वीकार करने के लिए संकलक की आवश्यकता होती है। "क्लास टेम्प्लेट या क्लास टेम्प्लेट के सदस्य की परिभाषा में, यदि क्लास टेम्प्लेट का बेस क्लास टेम्प्लेट-पैरामीटर पर निर्भर करता है, तो बेस क्लास स्कोप को अयोग्य नाम लुकअप के दौरान या तो परिभाषा के बिंदु पर जांचा नहीं जाता है। वर्ग टेम्पलेट या सदस्य या वर्ग टेम्पलेट या सदस्य की तात्कालिकता के दौरान। " [१४.६.२ / ३, सी ++ ०३]

@ रॉजर पटे: मैं उस नियम से अनभिज्ञ था। यह अब तय हो गया है।
rlbond

1
template <typename T> size_t bytesize(std::vector<T> const& v) { return sizeof(T) * v.size(); }

यदि आपको बहुत सारे फ़ंक्शंस का उपयोग करने की आवश्यकता है जो सूचक + बाइट्स की संख्या लेते हैं, तो यह हमेशा होता है

fun(vec.data(), bytesize(vec));

1

* के साथ एक स्ट्रिंग डुप्लिकेट करें:

std::string operator*(std::string s, size_t n)
{
    std::stringstream ss;
    for (size_t i=0; i<n; i++) ss << s;
    return ss.str();
}

0

मेरे पसंदीदा में से एक Transposerयह है कि एक ही आकार के कंटेनर के टपल का एक संक्रमण पाता है। यही है, अगर आपके पास एक है tuple<vector<int>,vector<float>>, तो यह इसे एक में परिवर्तित करता है vector<tuple<int, float>>। XML प्रोग्रामिंग में काम आता है। यहाँ देखें कि मैंने यह कैसे किया।

#include <iostream>
#include <iterator>
#include <vector>
#include <list>
#include <algorithm>
#include <stdexcept>

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <boost/type_traits.hpp>

using namespace boost;

template <class TupleOfVectors>
struct GetTransposeTuple;

template <>
struct GetTransposeTuple<tuples::null_type>
{
  typedef tuples::null_type type;
};

template <class TupleOfVectors>
struct GetTransposeTuple
{
  typedef typename TupleOfVectors::head_type Head;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef typename
    tuples::cons<typename remove_reference<Head>::type::value_type,
                 typename GetTransposeTuple<Tail>::type> type;
};

template <class TupleOfVectors,
          class ValueTypeTuple = 
                typename GetTransposeTuple<TupleOfVectors>::type,
          unsigned int TUPLE_INDEX = 0>
struct Transposer
  : Transposer <typename TupleOfVectors::tail_type,
                ValueTypeTuple,
                TUPLE_INDEX + 1>
{
  typedef typename remove_reference<typename TupleOfVectors::head_type>::type
    HeadContainer;
  typedef typename TupleOfVectors::tail_type Tail;
  typedef Transposer<Tail, ValueTypeTuple, TUPLE_INDEX + 1> super;
  typedef std::vector<ValueTypeTuple> Transpose;

  Transposer(TupleOfVectors const & tuple)
    : super(tuple.get_tail()),
      head_container_(tuple.get_head()),
      head_iter_(head_container_.begin())
  {}

  Transpose get_transpose ()
  {
    Transpose tran;
    tran.reserve(head_container_.size());
    for(typename HeadContainer::const_iterator iter = head_container_.begin();
        iter != head_container_.end();
        ++iter)
    {
      ValueTypeTuple vtuple;
      this->populate_tuple(vtuple);
      tran.push_back(vtuple);
    }
    return tran;
  }

private:

  HeadContainer const & head_container_;
  typename HeadContainer::const_iterator head_iter_;

protected:

  void populate_tuple(ValueTypeTuple & vtuple)
  {
    if(head_iter_ == head_container_.end())
      throw std::runtime_error("Container bound exceeded.");
    else
    {
      vtuple.get<TUPLE_INDEX>() = *head_iter_++;
      super::populate_tuple (vtuple);
    }
  }
};

template <class ValueTypeTuple,
          unsigned int INDEX>
struct Transposer <tuples::null_type, ValueTypeTuple, INDEX>
{
  void populate_tuple(ValueTypeTuple &) {}
  Transposer (tuples::null_type const &) {}
};

template <class TupleOfVectors>
typename Transposer<TupleOfVectors>::Transpose
transpose (TupleOfVectors const & tupleofv)
{
  return Transposer<TupleOfVectors>(tupleofv).get_transpose();
}

int main (void)
{
  typedef std::vector<int> Vint;
  typedef std::list<float> Lfloat;
  typedef std::vector<long> Vlong;

  Vint vint;
  Lfloat lfloat;
  Vlong vlong;

  std::generate_n(std::back_inserter(vint), 10, rand);
  std::generate_n(std::back_inserter(lfloat), 10, rand);
  std::generate_n(std::back_inserter(vlong), 10, rand);

  typedef tuples::tuple<Vint, Lfloat, Vlong> TupleOfV;
  typedef GetTransposeTuple<TupleOfV>::type TransposeTuple;

  Transposer<TupleOfV>::Transpose tran = 
    transpose(make_tuple(vint, lfloat, vlong));
  // Or alternatively to avoid copying
  // transpose(make_tuple(ref(vint), ref(lfloat), ref(vlong)));
  std::copy(tran.begin(), tran.end(),
            std::ostream_iterator<TransposeTuple>(std::cout, "\n"));

  return 0;
}

0

सुनिश्चित नहीं हैं कि अगर ये std रैपर के रूप में योग्य हैं, लेकिन मेरे आमतौर पर उपयोग किए जाने वाले सहायक कार्य हैं:

void split(string s, vector<string> parts, string delims);
string join(vector<string>& parts, string delim);
int find(T& array, const V& value);
void assert(bool condition, string message);
V clamp(V value, V minvalue, V maxvalue);
string replace(string s, string from, string to);
const char* stristr(const char* a,const char*b);
string trim(string str);
T::value_type& dyn(T& array,int index);

टी और वी यहाँ टेम्पलेट तर्क हैं। अंतिम फ़ंक्शन ठीक उसी तरह काम करता है, जैसा कि [] -ऑपरेटर, लेकिन स्वचालित रूप से आवश्यक इंडेक्स के आकार बदलने के साथ।


1
इस नाम के मैक्रो के लिए मानक पुस्तकालय द्वारा 'अस्सर' नाम आरक्षित है (सभी स्कोप में)।

1
मुझे लगता है कि विंडोज़ या mfc हेडर में घोषित मुखर () मैक्रो भी है। WM_PAINT इवेंट में दोनों विफल हो जाते हैं, क्योंकि जोरदार संवाद प्रदर्शित करने से कुछ मामलों में अगला आश्वासन मिलता है। इसलिए अंत में, उन छोटी गाड़ी के कार्यान्वयन को तीसरे के साथ बदलना कोई बड़ी बात नहीं है। आपको बस स्पष्ट रूप से #include <assert> के बाद खुद के मुखर-मैक्रो को फिर से परिभाषित करना है, या बस #undef मुखर का उपयोग करना है।
आरेप

0

पहले लोगों ने जो पोस्ट किया था, उसके समान, मेरे पास पासिंग तर्कों को सरल बनाने के लिए एल्गोरिदम के ओवरलोड हैं। मैं इस तरह के एल्गोरिदम को कॉल करता हूं:

for_each(iseq(vec), do_it());

मैंने सभी एल्गोरिदम को ओवरलोड किया, जैसे कि वे input_sequence_range<>दो इनपुट पुनरावृत्तियों के बजाय एकल प्रकार का एक पैरामीटर लेते हैं (इनपुट कुछ भी नहीं है जो केवल आउटपुट नहीं है)।

template<typename In>
struct input_sequence_range
: public std::pair<In,In>
{
    input_sequence_range(In first, In last)
        : std::pair<In,In>(first, last)
    { }
};

और यह है कि कैसे iseq()काम करता है:

template<typename C>
input_sequence_range<typename C::const_iterator> iseq(const C& c)
{
    return input_sequence_range<typename C::const_iterator>(c.begin(),
                                                            c.end());
}

इसी तरह, मेरे पास विशेषज्ञता है

  • const_iterators
  • संकेत (आदिम सरणियाँ)
  • स्ट्रीम पुनरावृत्तियों
  • कोई भी सीमा [आरंभ, अंत) केवल एक समान उपयोग के लिए: सब कुछ के लिए iseq () का उपयोग करें

3
... या आप बस Boost.Range का उपयोग कर सकते हैं और व्यापक रूप से परीक्षण किए गए कोड एडेप्टर और पीयर की समीक्षा प्राप्त कर सकते हैं।
मकर संक्रांति

0

के लिए अनियंत्रित मिटा std::vector। किसी तत्व को किसी तत्व से मिटाने का सबसे कारगर तरीका है vector, वह तत्वों के क्रम को संरक्षित नहीं करता है। मैंने इसे अन्य कंटेनरों में विस्तारित करने का बिंदु नहीं देखा क्योंकि अधिकांश में बीच से वस्तुओं को हटाने के लिए समान जुर्माना नहीं है। यह पहले से ही पोस्ट किए गए कुछ अन्य टेम्प्लेट के समान है लेकिन यह std::swapकॉपी करने के बजाय आइटम को स्थानांतरित करने के लिए उपयोग करता है।

template<typename T>
void unordered_erase(std::vector<T>& vec, const typename std::vector<T>::iterator& it)
{
    if (it != vec.end()) // if vec is empty, begin() == end()
    {
        std::swap(vec.back(), *it);
        vec.pop_back();
    }
}

साइनम एक प्रकार का संकेत देता है। -1नकारात्मक के लिए, 0शून्य के लिए और 1सकारात्मक के लिए रिटर्न ।

template <typename T>
int signum(T val)
{
    return (val > T(0)) - (val < T(0));
}

क्लैम्प बहुत आत्म व्याख्यात्मक है, यह एक मूल्य को जकड़ देता है ताकि यह दी गई सीमा के भीतर हो। यह मेरे दिमाग को चकरा देता है कि स्टैंडर्ड लाइब्रेरी में क्या शामिल है minऔर क्या maxनहींclamp

template<typename T>
T clamp(const T& value, const T& lower, const T& upper)
{
    return value < lower ? lower : (value > upper ? upper : value);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.