2012-07-13 17 views
16
#include <iostream> 
#include <type_traits> 

double f(int i) 
{ 
     return i+0.1; 
} 

struct F 
{ 
     public: 
     double operator()(int i) { return i+0.1; } 
}; 

int 
main(int, char**) 
{ 
     std::result_of<F(int)>::type x;  // ok 
     // std::result_of<f(int)>::type x; // error: template argument 1 is invalid 
     x = 0.1; 
     std::cerr << x << std::endl; 
} 

कृपया बताएं कि क्यों std::result_of<f(int)>::type x; अमान्य है ...std :: सरल समारोह result_of

cppreference कहते हैं, "(std::result_of) संकलन प्रकार में आयोजित एक समारोह कॉल अभिव्यक्ति की वापसी प्रकार deduces।"।

समस्या क्या है?

+3

समाधान इस 'std :: result_of :: टाइप x; '। यदि आप गहरी समझ चाहते हैं, तो इस प्रश्न को http://stackoverflow.com/q/2763824/893693 पर देखें – inf

उत्तर

22

std::result_of<T> को T एक प्रकार होने के लिए आवश्यक है - लेकिन किसी भी प्रकार का नहीं।

template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>; 

ऐसी है कि: T एक समारोह प्रकार तो result_of की इस आंशिक विशेषज्ञता का उपयोग किया जाएगा होना चाहिए

decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...)) 

अच्छी तरह से गठित है (सी ++ 11 20.9.7.6) । (INVOKE को 20.8.2 में परिभाषित किया गया है।)

कारण std::result_of<f(int)> काम नहीं करता है क्योंकि f एक प्रकार नहीं है - यह एक फ़ंक्शन प्रकार का उदाहरण है। x घोषित करने के लिए f की वापसी प्रकार एक int के लिए लागू किया जा करने के लिए, बस इस बारे में:

decltype(f(int{})) x; 

या यदि आप हार्ड-कोड एक int पसंद करते हैं:

decltype(f(32)) x; 

हैं प्रकार f का वांछित है तो उपयोग करें:

using FuncPtr = decltype(f); 

प्रदान की कोड F (अर्थात, नहीं लोअर केस f) में हालांकि एक प्रकार है और इसलिए F(int) एक प्रकार समारोह है कि F रिटर्न एक तर्क के रूप में एक int को स्वीकार करने का प्रतिनिधित्व करने को परिभाषित करता है। जाहिर है यह एफ नहीं है! F का प्रकार एक संरचना है जिसका उदाहरण फ़ंक्शन कॉल ऑपरेटर का उपयोग कर सकता है। F में int आदि भी कोई स्पष्ट या निहित रचनाकार नहीं है। यह कैसे काम कर सकता है? संक्षिप्त उत्तर: टेम्पलेट "जादू"।

अनिवार्य रूप से, std::result_of की परिभाषा, प्रकार लेता F(int) और इसलिए यह तय कर सकते हैं आह्वान के जो मामले() यह काम करने की अनुमति होगी तर्क प्रकार से वापसी प्रकार अलग करती है। आह्वान के मामलों रहे हैं: यदि केवल एक ही तर्क है

  1. एफ कुछ वर्ग टी
  2. के लिए एक सदस्य के कार्य करने के लिए एक सूचक है, एफ वर्ग टी के एक डेटा सदस्य के लिए एक सूचक है, या,
  3. एफ का एक उदाहरण, एक समारोह, यानी के रूप में इस्तेमाल किया जा सकता
declval<F>()(declval<int>()) 

जो एक सामान्य समारोह कॉल या functor किसी प्रकार (जैसे, अपने उदाहरण की तरह) हो सकता है।

एक बार यह निर्धारित किया गया है कि result_of मान्य अभिव्यक्ति का रिटर्न प्रकार निर्धारित कर सकता है। यह result_of के type सदस्य के माध्यम से वापस किया जाता है।

इस बारे में सुंदर बात यह है कि result_of के उपयोगकर्ता को यह वास्तव में काम करने के तरीके के बारे में कुछ भी पता नहीं होना चाहिए। केवल एक चीज को समझना है कि result_of को एक कार्य TYPE की आवश्यकता है। यदि कोई ऐसे नामों का उपयोग कर रहा है जो कोड के भीतर प्रकार नहीं हैं (उदा।, f) तो decltype को अभिव्यक्ति के प्रकार को प्राप्त करने के लिए उपयोग करने की आवश्यकता होगी।

अंत में, कारण f को एक प्रकार के रूप में नहीं माना जा सकता है क्योंकि टेम्पलेट पैरामीटर निरंतर मानों को भी अनुमति देते हैं और f एक स्थिर फ़ंक्शन पॉइंटर मान है। यह आसानी से प्रदर्शित किया गया है (f के सवाल की परिभाषा का उपयोग करते हुए):

std::cout << invoke_op<f>(10) << std::endl; 

तो ठीक से कुछ int साथ f लागू एक अभिव्यक्ति की वापसी मान प्रकार प्राप्त करने के लिए:

template <double Op(int)> 
double invoke_op(int i) 
{ 
    return Op(i); 
} 

और बाद में एक लिखेंगे:

decltype(f(int{})) 

(नोट: f कभी नहीं कहा जाता है: संकलक बस अपने परिणाम निर्धारित करने के लिए decltype भीतर अभिव्यक्ति का उपयोग करता है यानी, इस उदाहरण में अपनी वापसी मान।)

संबंधित मुद्दे