2012-11-10 16 views
5
template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) { 
    return x * y; 
} 

कोड का यह टुकड़ा स्ट्रॉस्ट्रप के C++11 FAQ से लिया गया था। मैं समझता हूं कि यह क्या करता है, जो विभिन्न प्रकार की दो वस्तुओं को गुणा करता है। टेम्पलेट पैरामीटर और फ़ंक्शन परिभाषा के बीच सिंटैक्स मुझे क्या परेशान करता है। decltype के अंदर क्या हो रहा है? मैं इसे लेता हूं कि यह एक अनमोल T पॉइंटर को 0 से शुरू किया गया है, और इसे बिना किसी नामित U पॉइंटर को गुणा किया जा रहा है और उसी तरह प्रारंभ किया गया है। क्या मैं सही हू?अज्ञात टेम्पलेट प्रकारों के साथ भ्रमित वाक्यविन्यास?

ठीक है, यदि यह हो रहा है, तो पॉइंटर्स, ड्रेरेन्शन और अतिरिक्त ब्रांड्स का उपयोग नहीं किया जाता है? मैं इस तरह प्रकार से प्रारंभ नहीं किया जा सका है, जबकि वांछित प्रभाव ?:

template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) { 
    return x * y; 
} 

यह बहुत मेरे लिए क्लीनर लग रहा है को बनाए रखने, और यह करता जब पहली में की तरह दो नंबर गुणा एक ही प्रभाव है ...

mul(4, 3); // 12 

तो क्यों Stroustrup जटिल सूचक, भिन्नता और आरंभीकरण सिंटेक्स के उपयोग पर जोर देते है? यह निश्चित रूप से, नए auto वाक्यविन्यास पेश करने से पहले है। लेकिन वैसे भी, मेरा प्रश्न है: क्या उपर्युक्त प्रकार के प्रारंभिक रूपों के बीच कोई अंतर है? जहां वह पॉइंटर्स का उपयोग करता है और जो कुछ मैंने किया है, उसके बजाए तुरंत उन्हें संदर्भित करता है, जो किसी भी पॉइंटर्स या डिफरेंसिंग वाले प्रकारों को प्रारंभ करना था? किसी भी प्रतिक्रिया की सराहना की है।

+0

क्या होता है जब 'टी' दिया जाता है जो 'int' से रचनात्मक नहीं है? –

उत्तर

6

आपका संस्करण समकक्ष नहीं है।

  1. आपका संस्करण supposes कि T और U दोनों 0 से निर्माण किया जा सकता। मैट्रिस से यह अपेक्षा करना गलत है, फिर भी उन्हें गुणा किया जा सकता है।
  2. T(0) एक अस्थायी उत्पन्न करता है (जो T&& से जुड़ा हो सकता है) जबकि *(T*(0)) किसी मौजूदा ऑब्जेक्ट (यानी T&) का संदर्भ उत्पन्न करता है, इसलिए एक अलग ऑपरेटर का चयन किया जा सकता है।

लेकिन दोनों ही ने Stroustrup के संस्करण है और न ही तुम्हारा अंत अभ्यास में इस्तेमाल किया जा रहा। संकलक कार्यान्वयन के एक बराबर स्तर पर, एक का प्रयोग करेंगे:

template <typename T, typename U> 
decltype(std::declval<T>() * std::declval<U>()) mul(T x, U y); 

लेकिन यह समारोह के तर्कों घोषणा के बाद देर वापसी प्रकार विनिर्देश का लाभ, वापसी प्रकार की घोषणा स्थगित अनुमति देने के लिए बनाया लेने में नाकाम रहने के है : auto f(int, int) -> int। एक बार तर्क घोषित किए जाने के बाद, वे का उपयोग कर सकते हैं, जो decltype के लिए अविश्वसनीय रूप से उपयोगी है!

template <typename T, typename U> 
auto mul(T x, U y) -> decltype(x * y); 

यह बाद प्रपत्र पुनरावृत्ति (दुर्भाग्य से) की कीमत पर, समारोह शरीर से एक ही ऑपरेटर अधिभार लेने के लिए गारंटी है।

+0

हमें 'std :: declval ()' के पैरामीटर में 0 क्यों नहीं रखना है? – 0x499602D2

+1

@ डेविड: 'अस्वीकरण' के लिए कोई तर्क नहीं है, इसलिए मुझे आपके प्रश्न को समझ में नहीं आता है, क्षमा करें: x –

+0

आप 'std :: declval () * std :: declval ()' लेकिन कैसे कर रहे हैं क्या हम जानते हैं कि ये संख्याएं हैं? जहां मैं 'टी (0) करता हूं 'मैं इसे 0 तक शुरू कर रहा हूं; हम 'अस्वीकरण' के मानकों में क्यों नहीं हैं? – 0x499602D2

5

कोड का आपका संस्करण मानता है कि टी और यू में डिफ़ॉल्ट निर्माता हैं। Stroustrup संस्करण नहीं है, यह एक शून्य सूचक को dereferencing द्वारा एक डमी वस्तु बनाता है। इससे कोई फर्क नहीं पड़ता क्योंकि वह कोड निष्पादित करने के लिए नहीं है, इसका मतलब केवल परिणामी प्रकार को जानने के लिए पार्स किया जाना है।

4

decltype सामग्री अनचाहे संदर्भ है; इससे कोई फर्क नहीं पड़ता कि वहां क्या है, जब तक कि यह एक प्रकार के साथ परिणाम न हो। एक दूसरे के बारे में T इस तरह परिभाषित किया जा रहा के लिए सोचो:

struct T 
{ 
    int operator*(const U &) { return 2; } 
}; 

यह निर्माता int या किसी भी प्रकार कि int के लिए परिवर्तनीय है लेने नहीं है; इसलिए, T(0) का परिणाम किसी ऑब्जेक्ट में नहीं होता है, यहां तक ​​कि decltype के अपरिहार्य संदर्भ में भी। इसलिए, अनगिनत शून्य संदर्भों का उपयोग संभवतः उचित प्रकार प्राप्त करने का सबसे आसान तरीका है।

नीचे पंक्ति: आप नहीं जानते कि निर्माता T और U क्या हैं, इसलिए आपको शून्य संदर्भ का उपयोग करना चाहिए जो उचित प्रकार के डमी ऑब्जेक्ट का संदर्भ देता है।

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