সি ++ তে সংখ্যার সাথে টেমপ্লেট বান্ধব স্ট্রিং


48

সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে স্ট্রিং থেকে সাংখ্যিক ধরণের রূপান্তর করতে ফাংশন রয়েছে:

stoi
stol
stoll
stoul
stoull
stof
stod
stold

তবে এগুলি টেম্পলেট কোডে ব্যবহার করা আমার কাছে ক্লান্তিকর মনে হচ্ছে। এখানে কোনও টেম্পলেট ফাংশন নেই কেন:

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

স্ট্রিংগুলিকে সংখ্যার ধরণের রূপান্তর করতে?

সেগুলি না থাকার কোনও প্রযুক্তিগত কারণ আমি দেখতে পাচ্ছি না, তবে সম্ভবত আমি কিছু মিস করছি। এগুলি অন্তর্নিহিত নামযুক্ত ফাংশনগুলিতে কল করতে এবং অ enable_if/ conceptsসংখ্যাবিহীন প্রকারকে অক্ষম করতে / ব্যবহার করতে বিশেষীকরণ করা যেতে পারে ।

স্ট্রিংকে সংখ্যাসূচক ধরণের রূপান্তর করতে এবং কার্যকরী উপায়ে অন্য উপায়ে কি কোনও টেমপ্লেট বান্ধব বিকল্প রয়েছে?



1
@ বুয়েথিয়োস সত্যই নয় - এই প্রশ্নের উত্তরগুলি "কেন" এর পিছনে যুক্তি ব্যাখ্যা করে, তবে তারা গৃহীত উত্তরের মতো ব্যবহারিক সমাধান দিয়ে আসে না। আমার যা প্রয়োজন তার চেয়ে আরও ভাল অবস্থার বিকল্প জিজ্ঞাসা করার জন্য আমি আমার প্রশ্নটি সম্পাদনা করেছি
মিরেসিয়া ইস্পাস

উত্তর:


40

এখানে কোনও টেম্পলেট ফাংশন নেই কেন:

সি ++ 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

এটি কোনও টেমপ্লেট নয় এবং এটি লোকালগুলির সাথে কাজ করে না তবে এটি যদি শো স্টপার না হয় তবে সি ++ 17 এর মধ্যে ইতিমধ্যে আপনার যা আছে তা রয়েছে: std::from_chars

পূর্ণসংখ্যার এবং ভাসমান-বিন্দু ধরণের সমস্তগুলির জন্য ওভারলোড রয়েছে এবং শেষ পরামিতিগুলি যথাক্রমে পূর্ণসংখ্যা এবং ভাসমান-পয়েন্ট ধরণের জন্য আলাদা (তবে যদি ডিফল্ট ঠিক থাকে তবে আপনার প্রয়োজন হবে না) কিছু পরিবর্তন করুন)। কারণ এটি কোনও স্থানীয়-সচেতন ফাংশন নয় এটি খুব দ্রুত। এটি রূপান্তর ফাংশনটিকে মান হিসাবে অন্যান্য স্ট্রিংয়ের কোনওটিকেই পরাজিত করবে এবং সাধারণত এটি আকারের আদেশ দ্বারা।

প্রায় একটি খুব ভাল CPPCON ভিডিও <charconv>(হেডার from_chars: এ জীবন) স্টিফেন টি Lavavej যে আপনি তার ব্যবহার এবং কর্মক্ষমতা সম্পর্কে এখানে দেখতে পারেন https://www.youtube.com/watch?v=4P_kbF0EbZM


1
@ নাথানঅলিভার: stoiএবং এর বন্ধুরা (প্রশ্নে বর্ণিত রূপান্তরগুলি) লোকেলগুলির সাথেও কাজ করে না, এটি কোনও শোস্টোপার নয়।
পিট বেকার

9

আপনি বেশি কিছু পাবেন না কারণ মত প্রকাশের মধ্যে

int x = sto("1");

টেমপ্লেট প্যারামিটারের জন্য কাঙ্ক্ষিত ধরণের অনুমিত করার কোনও (সহজ) উপায় নেই। আপনাকে লিখতে হবে

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

যা কিছুটা বাড়িয়ে জেনেরিক ফাংশন সরবরাহের উদ্দেশ্যকে পরাস্ত করে। অন্যদিকে, ক

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

আপনি যেমন বুঝতে পেরেছিলেন তেমন কাজে আসবে। সি ++ 17 এ রয়েছে std::from_charsযা কমবেশি ঠিক এমনটি করে (এটি কোনও টেমপ্লেট নয় বরং ওভারলোডের সেট এবং এটি স্ট্রিংয়ের পরিবর্তে চরগুলিতে পয়েন্টার নেয়, তবে কেবলমাত্র ছোটখাটো বিশদ বিবরণ দেয়)।

পিএস উপরের অভিব্যক্তিতে পছন্দসই ধরণের অনুমিত করার কোনও সহজ উপায় নেই তবে একটি উপায় আছে। আমি মনে করি না যে আপনার প্রশ্নের মূলটি হ'ল স্বাক্ষরটি যা আপনি চেয়েছিলেন, এবং আমি এটির প্রয়োগের জন্য নীচেরটি একটি ভাল উপায় বলে মনে করি না, তবে আমি জানতাম যে উপরের 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এর পদক্ষেপের শব্দার্থবিজ্ঞানের উপর নির্ভর করুন ।
এমসাল্টার

@ ক্ষুদ্র ব্যক্তিরা হ্যাঁ, এটিই আমি উল্লেখ করেছি যে সমস্যাটি সমস্যাযুক্ত, তবে আপনি ঠিক বলেছেন, কোনও রেফারেন্স ব্যবহার করার দরকার নেই। আসলে যা আমাকে আরও বিরক্ত করে তা হ'ল এটি একটি ফাংশন হিসাবে উপস্থিত হয় তবে আসল কার্যকারিতা রয়েছে converter, এছাড়াও আমি নিশ্চিত নই যে টেম্পলেট রূপান্তরকারী অপারেটরটি ব্যবহার করা সবচেয়ে ভাল পছন্দ ছিল, যে জিনিসগুলি স্থির করা যেতে পারে। আমি শুরুতে ভেবেছিলাম এটি
এতটা

আমি মনে করি না এখানে কনস্টের রেফারেন্স নিয়ে কোনও সমস্যা আছে। আমার বোধগম্যতা হল কনভার্টটি ধ্বংস না হওয়া অবধি কনস্টের রেফারেন্স স্ট্রিংয়ের আজীবন রক্ষা করবে ( herbsutter.com/2008/01/01/… )
bremen_matt

5

সমাধান সকলের সাথে সামঞ্জস্যপূর্ণ (এমনকি পুরানো সি ++ কম্পাইলারগুলির মতো সি ++ - 98 টিও ) বুস্ট :: লেক্সিক্যাল_কাস্ট ব্যবহার করা যা এটি উভয় উপায়ে সংখ্যাসূচক এবং স্ট্রিংয়ের মধ্যে রূপান্তর করতে একটি টেমপ্লেট।

উদাহরণ:

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

পুরানো সি ++ সংস্করণে, স্ট্রিং স্ট্রিমটি আপনার বন্ধু। যদি আমি সঠিকভাবে বুঝতে পারি তবে নিম্নলিখিতগুলি আপনার জন্য আকর্ষণীয় হতে পারে। এটি সি ++ 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;
}

এই পদ্ধতিটি সি ++ 11 এ কাজ করে এবং বেশ সাধারণ। আমার অভিজ্ঞতায়, এই পদ্ধতিটি শক্ত, তবে সবচেয়ে পারফর্ম্যান্ট নয়।


হ্যাঁ, এটি আমি ব্যবহার করেছি, তবে নীচে
নামকরণগুলি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.