C ++ में संख्यात्मक के लिए टेम्पलेट अनुकूल स्ट्रिंग


48

C ++ मानक पुस्तकालय में स्ट्रिंग से संख्यात्मक प्रकार में परिवर्तित करने के लिए कार्य हैं:

stoi
stol
stoll
stoul
stoull
stof
stod
stold

लेकिन मुझे टेम्पलेट कोड में उनका उपयोग करना थकाऊ लगता है। कोई टेम्पलेट फ़ंक्शंस क्यों नहीं हैं जैसे:

template<typename T>
T sto(...)

संख्यात्मक प्रकारों में तार बदलने के लिए?

मैं उन्हें नहीं करने के लिए कोई तकनीकी कारण नहीं देखता, लेकिन शायद मैं कुछ याद कर रहा हूँ। उन्हें अंतर्निहित नाम कार्यों को कॉल करने और गैर-संख्यात्मक प्रकारों को अक्षम करने के लिए उपयोग enable_if/ conceptsकरने के लिए विशेष किया जा सकता है ।

क्या मानक पुस्तकालय में स्ट्रिंग को सांख्यिक प्रकारों में बदलने और किसी कुशल तरीके से इधर-उधर करने के लिए कोई टेम्पलेट अनुकूल विकल्प हैं?


क्या इससे आपके सवाल का जवाब मिलता है? क्यों `std :: sto` ... श्रृंखला कोई टेम्पलेट नहीं है?
बोइथियोस

1
@Boiethios वास्तव में नहीं है - उस प्रश्न के उत्तर "क्यों" के पीछे तर्क को स्पष्ट करते हैं, लेकिन वे स्वीकृत उत्तर जैसे व्यावहारिक समाधान के साथ नहीं आते हैं। मैंने अपने प्रश्न को बेहतर स्थिति के विकल्प के लिए संपादित करने के लिए कहा है कि मुझे क्या चाहिए
Mircea Ispas

जवाबों:


40

कोई टेम्पलेट फ़ंक्शंस क्यों नहीं हैं जैसे:

C ++ 17 में ऐसे जेनेरिक स्ट्रिंग टू नंबर फंक्शन हैं, लेकिन नाम अलग-अलग हैं। वे साथ गए std::from_chars, जो सभी संख्यात्मक प्रकारों के लिए अतिभारित है।

जैसा कि आप देख सकते हैं, पहला अधिभार किसी भी पूर्णांक प्रकार को आउटपुट पैरामीटर के रूप में ले रहा है और यदि संभव हो तो इसके लिए मान निर्दिष्ट करेगा।

इसका उपयोग इस तरह किया जा सकता है:

template<typename Numeric>
void stuff(std::string_view s) {
    auto value = Numeric{};

    auto [ptr, error] = std::from_chars(s.data(), s.data() + s.size(), value);

    if (error) {
        // error with the conversion
    } else {
        // conversion successful, do stuff with value
    }
}

जैसा कि आप देख सकते हैं, यह सामान्य संदर्भ में काम कर सकता है।



1
बेशक! यहां तक ​​कि यह सरल संरचना के साथ काम करता है या यदि सही इंटरफ़ेस, कक्षाएं भी दी जाती हैं।
गिलियूम रेसिकोस्ट

13

यह कोई टेम्प्लेट नहीं है, और यह स्थानों के साथ काम नहीं करता है, लेकिन अगर यह शो स्टॉपर नहीं है, तो C ++ 17 में पहले से ही आप क्या चाहते हैं: std::from_chars

सभी पूर्णांक और फ़्लोटिंग-पॉइंट प्रकारों के लिए ओवरलोड हैं और इंटरफ़ेस अंतिम पैरामीटर को छोड़कर समान है जो क्रमशः पूर्णांक और फ़्लोटिंग-पॉइंट प्रकारों के लिए अलग हैं (लेकिन यदि डिफ़ॉल्ट ठीक है, तो आपको इसकी आवश्यकता नहीं है कुछ भी बदलो)। क्योंकि यह एक लोक-जागरूक कार्य नहीं है, यह काफी तेज है। यह रूपांतरण प्रक्रिया के लिए किसी अन्य स्ट्रिंग को हरा देगा और आम तौर पर यह परिमाण के आदेशों द्वारा होता है।

Stephan T. Lavavej द्वारा CPPCON वीडियो के बारे में एक बहुत अच्छा वीडियो है <charconv>(हैडर from_charsरहता है) जिसे आप इसके उपयोग और प्रदर्शन के बारे में यहाँ देख सकते हैं: https://www.youtube.com/watch?v=4P_kbF0EbZM


1
@NathanOliver: stoiऔर इसके दोस्त (प्रश्न में उल्लेखित रूपांतरण) भी स्थानों के साथ काम नहीं करते हैं, इसलिए यह शोकेस नहीं है।
पीट बेकर

9

क्योंकि आप एक अभिव्यक्ति में ज्यादा हासिल नहीं करेंगे

int x = sto("1");

टेम्पलेट पैरामीटर के लिए वांछित प्रकार को घटाने का कोई (आसान) तरीका नहीं है। आपको लिखना होगा

int x = sto<int>("1");

जो कुछ विस्तार में एक सामान्य कार्य प्रदान करने के उद्देश्य को पराजित करता है। दूसरी ओर, ए

template<typename T>
void sto(std::string x,T& t);

जैसा कि आपने महसूस किया अच्छा उपयोग होगा। C ++ 17 में हैstd::from_chars , जो कमोबेश यही करता है (यह कोई टेम्प्लेट नहीं है, लेकिन ओवरलोड का एक सेट है और यह स्ट्रिंग के बजाय संकेत पर ले जाता है, लेकिन यह केवल मामूली विवरण है)।

PS उपरोक्त अभिव्यक्ति में वांछित प्रकार को कम करने का कोई आसान तरीका नहीं है, लेकिन एक तरीका है। मुझे नहीं लगता कि आपके प्रश्न का मूल आप के लिए हस्ताक्षर था, और मुझे नहीं लगता कि निम्नलिखित इसे लागू करने का एक अच्छा तरीका है, लेकिन मुझे पता था कि उपरोक्त int x = sto("1");संकलन करने का एक तरीका है और मैं इसे देखने के लिए उत्सुक था। कार्रवाई में।

#include <iostream>
#include <string>

struct converter {
    const std::string& x;
    template <typename T> operator T() { return 0;}
};

template <> converter::operator int() { return stoi(x); }
template <> converter::operator double() { return stod(x); }
converter sto(const std::string& x) { return {x}; }

int main() {
    std::string s{"1.23"};
    int x = sto(s);
    double y = sto(s);
    std::cout << x << " " << y;
}

यह इरादा के अनुसार काम करता है, लेकिन इसमें गंभीर गिरावट है, शायद सबसे महत्वपूर्ण रूप से यह लिखने की अनुमति देता है auto x = sto(s);, अर्थात गलत का उपयोग करना आसान है।


मुझे लगता है कि यहां निहित रूपांतरण पर भरोसा करना एक अच्छा विचार है। ऑटो को अक्षम करने की कोशिश करना एक समस्या है। आमतौर पर, मैंने देखा है कि एक कक्षा में एक निजी कॉन्स्ट रेफरेंस डालकर किया जाता है जो केवल मान्य विधियों द्वारा आरंभ किया जाता है। मैं यह नहीं देख सकता कि कोई इस बात का लाभ कैसे उठाएगा, क्योंकि आगे बढ़ने से पहले हमें एक संपूर्ण कनवर्टर ऑब्जेक्ट का निर्माण करना होगा।
हम्मम

मैं गैर-कटौती प्रकार पैरामीटर के बावजूद मान देख सकता हूं - जैसा कि सवाल कहता है, प्रेरणा टेम्पलेट कोड के भीतर से उपयोग करने में सक्षम है, जहां आप एक प्रकार में परिवर्तित कर रहे हैं जो तात्कालिकता के बीच भिन्न होता है।
टॉबी स्पीट

मौलिक समस्या क्या है auto x = sto(s)? यह विशेष रूप से कार्यान्वयन टूट जाता है क्योंकि converter::xएक संदर्भ है जो दायरे से बाहर हो जाता है, लेकिन यह निश्चित है। बस संदर्भ को हटा दें और std::string'' शब्दार्थ शब्दार्थ पर भरोसा करें ।
MSalters

@MSalters हाँ, यह संदर्भ था जो मुझे लगा कि समस्याग्रस्त है, लेकिन आप सही हैं, संदर्भ का उपयोग करने की आवश्यकता नहीं है। वास्तव में जो मुझे अधिक परेशान करता है वह यह है कि यह एक फ़ंक्शन प्रतीत होता है लेकिन वास्तविक कार्यक्षमता में है converter, यह भी मुझे यकीन नहीं है कि एक टेम्पलेट रूपांतरण ऑपरेटर का उपयोग करना सबसे अच्छा विकल्प था, जो चीजें तय की जा सकती थीं। हो सकता है कि यह बुरा न हो जैसा कि मैंने शुरू में सोचा था
idclev 463035818

मुझे नहीं लगता कि यहां कॉन्स्ट रेफरेंस को लेकर कोई समस्या है। मेरी समझ यह है कि कॉन्स्ट रेफरेंस स्ट्रिंग के जीवनकाल को तब तक संरक्षित रखेगा जब तक कि कन्वर्टर नष्ट नहीं हो जाता ( हर्ब्सट्यूटर
2008

5

सभी के साथ संगत समाधान (C ++ - 98 वाले जैसे पुराने C ++ कंपाइलर) को बढ़ावा देने के लिए उपयोग किया जाता है :: lexical_cast जो दोनों तरह से संख्यात्मक और स्ट्रिंग प्रकारों के बीच कनवर्ट करने के लिए एक टेम्पलेट है।

उदाहरण:

short myInt = boost::lexical_cast<short>(*argv);
std::string backToString = boost::lexical_cast<std::string>(myInt);

देखें: https://www.boost.org/doc/libs/1_42_0/libs/conversion/lexical_cast.htm


3

पुराने C ++ संस्करणों पर, स्ट्रिंगस्ट्रीम आपका मित्र है। अगर मैं सही तरीके से समझूं, तो निम्नलिखित आपके लिए दिलचस्प हो सकता है। यह C ++ 11 है।

https://wandbox.org/permlink/nUNiUwWWTr7a0NXM

#include <sstream>
#include <string>
#include <iostream>

template<typename T, typename String>
T sto(const String & str) {
    T val;
    std::stringstream ss(str);
    ss >> val;
    return val;
}

template<typename T, typename String>
void sto(const String & str, T & val) {
    std::stringstream ss(str);
    ss >> val;
}

int main() {   
    std::cout << sto<float>("1.1") << ", " << sto<int>(std::string{"2"});

    // An alternative version that infers the type 
    double d;
    sto("3.3", d);
    std::cout << ", " << d;
}

यह विधि C ++ 11 में काम करती है और बहुत सामान्य है। मेरे अनुभव में, यह तरीका अधिक मजबूत है, लेकिन सबसे अधिक प्रदर्शन करने वाला नहीं है।


हां, यह वही है जो मैंने उपयोग किया है, लेकिन प्रदर्शन नामित कार्यों के नीचे है जो कभी-कभी वांछित नहीं होता है
Mircea Ispas
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.