Std :: result_of और घोषणापत्र के बीच अंतर


100

मुझे std::result_ofC ++ 0x की आवश्यकता को समझने में कुछ परेशानी है । अगर मुझे सही तरीके से समझा जाता है, result_ofतो कुछ प्रकार के मापदंडों के साथ फ़ंक्शन ऑब्जेक्ट को लागू करने के परिणामस्वरूप प्रकार प्राप्त करने के लिए उपयोग किया जाता है। उदाहरण के लिए:

template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
    return f(a);
}

मैं वास्तव में निम्नलिखित कोड के साथ अंतर नहीं देखता:

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
    return f(a);
}

या

template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
    return f(a);
}

एकमात्र समस्या जो मैं इन दो समाधानों के साथ देख सकता हूं, वह है:

  • डिक्लेयर करने के लिए पास किए गए एक्सप्रेशन में इसका उपयोग करने के लिए फ़नकार का एक उदाहरण है।
  • फ़न्क्टर के लिए एक परिभाषित कंस्ट्रक्टर को जानें।

क्या मैं यह सोचने में सही हूं कि क्या केवल एक अंतर है decltypeऔर result_ofपहला यह कि अभिव्यक्ति की आवश्यकता है जबकि दूसरी नहीं?

जवाबों:


86

result_ofबूस्ट में पेश किया गया था , और फिर TR1 में शामिल किया गया था , और अंत में C ++ 0x में। इसलिए result_ofएक फायदा है कि पिछड़े-संगत (एक उपयुक्त पुस्तकालय के साथ)।

decltype C ++ 0x में एक पूरी तरह से नई चीज़ है, यह केवल एक फ़ंक्शन के प्रकार को वापस करने के लिए प्रतिबंधित नहीं करता है, और एक भाषा सुविधा है।


वैसे भी, gcc 4.5 पर, के result_ofसंदर्भ में लागू किया गया है decltype:

  template<typename _Signature>
    class result_of;

  template<typename _Functor, typename... _ArgTypes>
    struct result_of<_Functor(_ArgTypes...)>
    {
      typedef
        decltype( std::declval<_Functor>()(std::declval<_ArgTypes>()...) )
        type;
    };

4
जहां तक ​​मैं समझता हूं कि decltypeयह बदसूरत है, लेकिन अधिक शक्तिशाली भी है। result_ofकेवल उन प्रकारों के लिए उपयोग किया जा सकता है जो कॉल करने योग्य हैं और उन्हें तर्क के रूप में प्रकारों की आवश्यकता होती है। उदाहरण के लिए, आप result_ofयहां उपयोग नहीं कर सकते हैं: template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );यदि तर्क अंकगणितीय प्रकार हो सकते हैं (ऐसा कोई कार्य नहीं है Fजिसे आप F(T,U)प्रतिनिधित्व करने के लिए परिभाषित करते हैं t+u। उपयोगकर्ता परिभाषित प्रकारों के लिए जो आप कर सकते हैं। उसी तरह से (मैं वास्तव में इसके साथ नहीं खेला है) मैं कल्पना करता हूं। सदस्य विधियों को कॉल करने के लिए result_ofबाइंडरों या
लैंबडास

2
एक नोट, घोषणापत्र को AFAIK के साथ फ़ंक्शन को कॉल करने के लिए तर्कों की आवश्यकता होती है, इसलिए बिना result_of <> बिना डिफ़ॉल्ट डिफ़ॉल्ट कंस्ट्रक्टर वाले तर्कों पर भरोसा किए बिना टेम्पलेट द्वारा लौटाए गए प्रकार को प्राप्त करना अजीब है।
रॉबर्ट मेसन

3
@RobertMason: उन तर्कों का उपयोग करके पुनर्प्राप्त किया जा सकता है std::declval, जैसा कि मैंने ऊपर दिखाया गया कोड। बेशक, यह बदसूरत है :)
kennytm

1
@ DavidRodríguez-dribeas आपकी टिप्पणी ने उन कोष्ठकों को खोल दिया है जो "(" है :(
नवीन

1
एक और नोट: result_ofऔर इसके सहायक प्रकार result_of_tको C ++ 17 के रूप में चित्रित किया गया है invoke_resultऔर invoke_result_t, पूर्व के कुछ प्रतिबंधों को कम करता है। ये en.cppreference.com/w/cpp/types/result_of के नीचे सूचीबद्ध हैं ।
सिग्मा

11

यदि आपको किसी ऐसी चीज़ की ज़रूरत है जो फ़ंक्शन कॉल जैसी कोई चीज़ नहीं है, तो std::result_ofबस लागू नहीं होती है। decltype()आप किसी भी अभिव्यक्ति का प्रकार दे सकते हैं।

यदि हम एक फ़ंक्शन कॉल (बीच std::result_of_t<F(Args...)>और decltype(std::declval<F>()(std::declval<Args>()...)) के रिटर्न प्रकार को निर्धारित करने के केवल विभिन्न तरीकों से खुद को प्रतिबंधित करते हैं , तो एक अंतर है।

std::result_of<F(Args...) की तरह परिभाषित किया गया है:

यदि अभिव्यक्ति INVOKE (declval<Fn>(), declval<ArgTypes>()...)को अच्छी तरह से बनाया जाता है, जब एक अनवैलेंटेड ऑपरेंड (क्लाज 5) के रूप में माना जाता है, तो सदस्य टाइप किए गए प्रकार का नाम decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...)); अन्यथा होगा, कोई सदस्य प्रकार नहीं होगा।

के बीच का अंतर result_of<F(Args..)>::typeऔर decltype(std::declval<F>()(std::declval<Args>()...)वह सब है INVOKE। का उपयोग करना declval/ decltypeसीधे, टाइप करने के लिए काफी लंबा होने के अलावा, केवल तभी मान्य है यदि Fसीधे कॉल करने योग्य है (एक फ़ंक्शन ऑब्जेक्ट प्रकार या फ़ंक्शन या फ़ंक्शन पॉइंटर)। result_ofइसके अतिरिक्त सदस्यों के कार्यों के लिए संकेत और सदस्य डेटा के लिए संकेत का समर्थन करता है।

प्रारंभ में, SFINAE के अनुकूल अभिव्यक्ति का उपयोग declval/ decltypeगारंटी, जबकि std::result_ofकटौती की विफलता के बजाय आपको एक कठिन त्रुटि दे सकती है। इसे C ++ 14 में सही किया गया है: std::result_ofअब SFINAE के अनुकूल होना आवश्यक है ( इस पेपर के लिए धन्यवाद )।

तो एक अनुरूप C ++ 14 संकलक पर, std::result_of_t<F(Args...)>सख्ती से बेहतर है। यह स्पष्ट, छोटा है, और सही ढंग से का समर्थन करता है और अधिक Fरों


That जब तक कि, आप इसे एक ऐसे संदर्भ में उपयोग कर रहे हैं जहाँ आप सदस्यों को संकेत देने की अनुमति नहीं देना चाहते हैं, तो std::result_of_tऐसे मामले में सफल होंगे जहाँ आप चाहते हैं कि यह विफल हो जाए।

Ions अपवादों के साथ। यदि यह सदस्यों को पॉइंटर्स का समर्थन करता है, result_ofतो यदि आप एक अमान्य प्रकार-आईडी को तत्काल करने का प्रयास करते हैं तो यह काम नहीं करेगा । इनमें एक फ़ंक्शन को वापस करना या मूल्य के अनुसार सार प्रकार लेना शामिल होगा। पूर्व .:

template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }

int answer() { return 42; }

call(answer); // nope

सही उपयोग हुआ होगा result_of_t<F&()>, लेकिन यह एक ऐसा विवरण है जिसे आपको याद नहीं रखना है decltype


एक गैर-संदर्भ प्रकार Tऔर एक फ़ंक्शन के लिए template<class F> result_of_t<F&&(T&&)> call(F&& f, T&& arg) { return std::forward<F>(f)(std::move(arg)); }, result_of_tसही का उपयोग है ?
Zizheng ताई

इसके अलावा, यदि हम जिस तर्क से गुजरते हैं fवह एक है const T, तो क्या हमें इसका उपयोग करना चाहिए result_of_t<F&&(const T&)>?
Zizheng ताई
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.