मेरे पास एक तरीका है जो एक वैकल्पिक संरचना देता है, जैसे:

auto getBook(const std::string &title) const -> std::optional<Book>;

मैं इस विधि को किसी अन्य विधि में कॉल करना चाहता हूं जो वैकल्पिक लेखक देता है। समस्या यह है कि कार्यान्वयन को हमेशा जांचना चाहिए कि क्या गेटबुक द्वारा लौटाया गया वैकल्पिक किसी विधि को कॉल करने से पहले भर जाता है, जैसे:

auto getAuthor(const std::string &title) const -> std::optional<Author>
{
   const auto optBook = getBook(title);
   if (optBook.has_value)
      return optBook->getAuthor();
   else
      return std::nullopt;
}

क्या इसे छोटे तरीके से लिखने का कोई तरीका है, ताकि यदि वैकल्पिक भर दिया जाए तो विधि कहलाती है, लेकिन यदि वैकल्पिक खाली है, तो std::nullopt वापस कर दिया जाता है। ऐसा कुछ (मुझे पता है कि यह वर्तमान में काम नहीं करता है लेकिन आपको मेरी बात समझ में आती है):

auto getAuthor(const std::string &title) const -> std::optional<Author>
{
   return getBook(title).getAuthor();
}
3
Patrick 23 अक्टूबर 2020, 15:44

4 जवाब

सबसे बढ़िया उत्तर

आप एक map फ़ंक्शन बनाकर इस पैटर्न को सामान्य कर सकते हैं, जो एक वैकल्पिक o और एक फ़ंक्शन f लेता है, और f(*o) का परिणाम देता है यदि o.has_value() == true:

template <typename O, typename F>
auto map(O&& o, F&& f) -> std::optional<decltype(f(*std::forward<O>(o)))>
{
    if (!o.has_value()) 
    {
        return {std::nullopt};
    }

    return {f(*std::forward<O>(o))};
}

फिर आप getAuthor को इस प्रकार परिभाषित कर सकते हैं:

auto getAuthor(const std::string& title) -> std::optional<Author>
{
    return map(getBook(title), [](Book b)
    {
        return b.author;
    });
}

Godbolt.org पर लाइव उदाहरण


मैंने इस तरह के ऑपरेशन के लिए एक लाइब्रेरी बनाई है, जिसका नाम है scelta। मेरे पुस्तकालय के साथ, आप लिख सकते हैं:

auto getBook(const std::string& title) -> std::optional<Book>;
auto getAuthor(const std::optional<Book>& title) -> std::optional<Author>;

using namespace scelta::infix;
std::optional<Author> a = getBook("...") | map(getAuthor);

अधिक जानकारी के लिए "Monadic वैकल्पिक संचालन" देखें।

8
Vittorio Romeo 23 अक्टूबर 2020, 17:26

मुझे लगता है कि आप जो चाहते हैं उसे वापस कर सकते हैं और रूट फ़ंक्शन में अपवादों को पकड़ सकते हैं, ऐसा कुछ:

auto  get_size_t(const bool state)
{
 return state ? std::optional<size_t>(std::rand()) : std::nullopt;
}

auto  get_string_size_t(const bool state)
{
 return std::optional<std::string>(std::to_string(get_size_t(state).value()));
}

void  f()
try
{
 std::clog << get_string_size_t(true).value() << std::endl;
 std::clog << get_string_size_t(false).value() << std::endl;
}
catch (...)
{
}

-1
Ghasem Ramezani 23 अक्टूबर 2020, 16:13

मुझे लगता है, अशक्त वस्तु यहां कार्य के लिए std::वैकल्पिक के बजाय पैटर्न की आवश्यकता है।

हाँ, यह std :: वैकल्पिक जैसा दिखता है, लेकिन एक अलग अर्थशास्त्र के साथ: जब किसी ऑब्जेक्ट पर किसी भी विधि (जैसे getAuthor) को कॉल किया जाता है, यदि विधि का परिणाम मान्य है, तो वैध ऑब्जेक्ट वापस कर दिया जाता है। यदि नहीं, तो इसके बजाय अशक्त वस्तु वापस कर दी जाती है।

बहुत समय पहले मैंने एक्सएमएल जैसे पेड़ के कार्यान्वयन पर काम नहीं किया था, यह ऐसा कुछ था:

auto val = object.node("root").node("branch_1").node("subbranch_1").toInt();
if (val) process(val.asInt());

नोड () कॉल के प्रत्येक चरण पर, यदि विशिष्ट नोड नहीं मिला, तो अमान्य नोड वापस कर दिया जाता है। जब इसे अमान्य नोड पर बुलाया जाता है, तो अमान्य नोड वापस कर दिया जाता है।

AFAIK, ऐसा कुछ भी वर्तमान में एसटीएल में लागू नहीं किया गया है।

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

संपादित करें: यह सभी मामलों के लिए सबसे अच्छा समाधान नहीं है, शायद, यह आपके लिए लागू करने के लिए बहुत जटिल है।

0
Leontyev Georgiy 23 अक्टूबर 2020, 16:27

boost::optional, जिस पर std::optional आधारित है, उसका एक सदस्य है map जो ऐसा करता है।

उदा.

auto getBook(const std::string &title) const -> boost::optional<Book>;

auto getAuthor(const std::string &title) const -> boost::optional<Author>
{
   return getBook(title).map(std::mem_fn(&Book::getAuthor));
}
0
Caleth 23 अक्टूबर 2020, 16:21