2012-08-20 9 views
9

यह सवाल एक और अधिक सार रास्ते में How to deduce the type of the functor's return value? की एक अनुवर्ती मैं इसे पुन: तैयार कर रहा हूँ है।एक मजेदार के रिटर्न प्रकार को कम करने के लिए सामान्य तरीका?

एक टेम्पलेट समारोह

template <typename Arg, typename Fn> 
auto ComputeSomething(Arg arg, Fn fn) -> decltype(<decl-expr>) 
{ 
// do something 
// ............ 
return fn(<ret-expr>) 
} 

जहां <ret-expr> एक मनमाना अभिव्यक्ति जो arg शामिल है, मैं <decl-expr> के लिए करते हैं जाएगा ComputeSomething की वापसी प्रकार functor की वापसी प्रकार के बराबर सेट करने के लिए की स्यूडोकोड को देखते हुए।

functor एक वर्ग, एक लैम्ब्डा या एक समारोह सूचक हो सकता है।

आंशिक समाधान मैं अब तक नहीं मिला।

(क) अपने सभी जुड़े हुए ecatmur द्वारा किया जाता प्रश्न के लिए जवाब। अनिवार्य रूप से, यह <decl-expr> में रिटर्न स्टेटमेंट दोहरा रहा है। समस्याएं: यह त्रुटि-प्रवण है और स्थानीय चर शामिल होने पर काम नहीं करेगा।

(b) यह समारोह संकेत के लिए ही काम करता है

template <typename Arg, typename Ret> 
Ret ComputeSomething(Arg arg, Ret(*fn)(Arg)) 

(ग) यह मानता है कि functor के तर्क (सामान्य रूप में पकड़ नहीं सकता है) प्रकार Arg की है और Arg की आवश्यकता है default- होने के लिए constructible

template <typename Arg, typename Fn> 
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(Arg()) 

(घ) std::declval का प्रयोग के रूप में how to deduce the return type of a function in template में सुझाव दिया है, जो डिफ़ॉल्ट-constructible प्रतिबंध लिफ्ट करने के लिए माना जाता है। क्या कोई यह समझा सकता है कि यह कैसे काम करता है?

template <typename Arg, typename Fn> 
auto ComputeSomething(Arg arg, Fn fn) -> decltype(fn(std::declval<Arg>()) 
+0

मैं यह कहना माफी चाहता हूँ, लेकिन AFAIK यह संभव नहीं है, क्योंकि अनुगामी वापसी नहीं देखता समारोह टेम्पलेट परिभाषित किया जा रहा है, जबकि शरीर करता है –

उत्तर

4

यहाँ अपने ही समाधान है, सबसे अच्छा मैं मिल सकता है

template <typename Arg, typename Fn> 
typename std::result_of<Fn(Arg)>::type ComputeSomething(Arg arg, Fn fn) 
10

उपयोग result_of। यह पीछे की तरफ संगत है और आपके कोड से सभी बदसूरत declval दर्द लेता है। यदि आप वास्तव में मूल्यों को आगे बढ़ाते हैं तो आपको अभी भी रैवल्यू संदर्भ क्वालीफायर (&&) जोड़ने की याद रखना होगा। बाकी

कुछ ऐसा जो मुझे महत्वपूर्ण लगता है: अपने समारोह एक और कार्य करने के लिए तर्क अग्रेषित करता है। ऐसे मामलों में आपको तर्कों को पारित करने के लिए हमेशा रावल संदर्भों का उपयोग करना चाहिए।

तो तुम सब करने की कोशिश कर रहे हैं रख-रखाव में सुधार है: वहाँ एक RETURNS मैक्रो चारों ओर कई प्रयास है कि वापसी प्रकार घोषणा और वास्तविक वापसी अभिव्यक्ति के बीच पुनरावृत्ति कम करने की कोशिश कर रहे हैं, लेकिन मैं किसी भी है कि अनुमति देता है नहीं देखा है एक फ़ंक्शन बॉडी जिसमें वास्तविक रिटर्न स्टेटमेंट से अधिक शामिल है।

कैसे declval कार्यों के लिए के रूप में: इसके संकलक निर्भर। इसे मूल्यांकन सामग्री में होने की अनुमति नहीं है और इसकी तर्क एक अपूर्ण प्रकार हो सकती है। 20.2.4

+0

मैं 'std :: result_of' के खिलाफ सलाह दूंगा। एक बार यह 'decltype'- आधारित समाधानों के विपरीत, SFINAE की गारंटी नहीं है। यह कॉल के परिणाम प्रकार को भी प्रतिबिंबित नहीं करता है - यह उससे अधिक करता है उदा। सदस्यों के लिए पॉइंटर्स के संबंध में। –

+0

@ ल्यूकडैंटन मैं हमेशा लाभ के रूप में "और अधिक" महसूस करता हूं। प्वाइंटर्स के सदस्य कार्यों के मामले को संभालना बेहद कठिन है और 'result_of' उस समस्या को हल करता है। क्या आप एसएफआईएनएई मुद्दे के बारे में विस्तार से जा सकते हैं? – pmr

+0

'std :: result_of' कंप्यूटिंग में कोई बिंदु नहीं है, परिणाम प्रकार फ़ंक्शन टेम्पलेट से निपट नहीं सकता है -' f (a, b, c) 'एक वाक्यविन्यास त्रुटि है जब' f' सदस्य के लिए सूचक होता है। एसएफआईएनएई के लिए, एक अधिभारित 'लागू' पर विचार करें, जैसे कि 'लागू (एफ, तर्क ...)' या तो परिणाम 'एफ (तर्क ...)' या यदि यह अच्छी तरह से गठित नहीं होता है, तो 'f (* तर्क ...) '(चलो सादगी के लिए मान लें कि उन दो अभिव्यक्तियों को कभी-कभी अच्छी तरह से गठित नहीं किया जाता है)। सफल होने के लिए कॉल के लिए अधिभार को हटाने के लिए आपको SFINAE की आवश्यकता है। –

2

(ख) के एक संस्करण देखें काम कर न केवल समारोह संकेत के साथ किया जाना चाहिए की तरह कुछ

template<typename Arg, typename Ret> 
Ret ComputeSomething (Arg arg, function<auto (Arg) -> Ret> f) 
3

बनाने के (ग) कुछ भी के लिए काम करता है, तो आप 2 भार के जरूरत है। 1 के रूप में में (ग) से पता चला, 2:

template <typename Arg, typename Ret> 
Ret ComputeSomething(Arg arg, std::function<Ret(Arg)> fn) 

इसके अलावा, gcc bug 54111 जैसे शो - वापसी प्रकार की कटौती बहुत अविश्वसनीय है।

11

std::declval एक फ़ंक्शन टेम्पलेट है जिसे केवल घोषित किया गया है (परिभाषित नहीं किया गया है)। इस प्रकार इसका उपयोग केवल अनियमित संदर्भों में किया जा सकता है जैसे sizeof और decltype पर तर्क। यह निर्दिष्ट प्रकार के एक रैल्यू वापस करने के लिए घोषित किया जाता है। यह आपको decltype अभिव्यक्ति में फ़ंक्शन कॉल के लिए डमी पैरामीटर बनाने के लिए इसका उपयोग करने की अनुमति देता है।

उदा

typedef decltype(fn(std::declval<Arg>())) t; 

t वाणी प्रकार Arg के एक rvalue साथ fn बुला का परिणाम के प्रकार किया जाना है। यह आपके मामले (सी) (fn(Arg())) के समान है, लेकिन इसे Arg की किसी भी चीज़ की आवश्यकता नहीं है, इसलिए यह डिफ़ॉल्ट कन्स्ट्रक्टर के बिना प्रकारों पर काम करता है।

यदि आपकी वापसी अभिव्यक्ति foo के स्थानीय चर का उपयोग करती है, तो आप कैसे बनाते हैं, इस पर ध्यान दिए बिना आप decltype(fn(std::declval<foo>())) का उपयोग कर सकते हैं।

यदि आपको नामांकित ऑब्जेक्ट या लवल्यू संदर्भ जैसे लेल्यू की आवश्यकता है, तो आप std::declval<foo&>() का उपयोग कर सकते हैं। यह आपको उस मामले को संभालने की अनुमति देता है जहां प्रकार इस बात पर निर्भर करता है कि आपके पास एक लवल्यू या रावल्यू है या नहीं।

+2

'std :: declval () 'कुछ भी माना जाना चाहिए, विशेष रूप से आप एक स्थानीय चर का उल्लेख करने पर विचार कर रहे हैं। –

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