2012-08-08 13 views
5

क्या सी ++ 11 में decltype के परिणाम की तुलना करने का कोई तरीका है?decltype तुलना

दूसरे शब्दों में, क्यों इस कोड अमान्य है:

template<typename T, typename U> 
void func(T& t, U& u) { 
    if(decltype(t) == decltype(u)) { 
     // Some optimised version for this case 
    } else { 
     // A more general case for differing types 
    } 
} 

मुझे पता है कि कुछ मामलों में इस विशेष समस्या आंशिक टेम्पलेट विशेषज्ञता द्वारा हल किया जा सकता है; मेरा प्रश्न decltype एस की तुलना के बारे में है।

संपादित करें: प्रश्न SFINAE के माध्यम से नि: शुल्क कार्यों के लिए डिफ़ॉल्ट प्रदान करने के प्रयास में आया था। शायद एक बेहतर सवाल हो गया होता क्यों यह अमान्य है:

template<bool B> 
bool SomeFunction() { ... } 

template<typename T, typename U> 
bool SomeFunctionWrapper(T& t, U& u) { 
    SomeFunction<decltype(t) == decltype(u)>(); 
} 

मैंने के बाद से एक और समाधान पाया (है कि सभी पर टेम्पलेट्स शामिल नहीं करता है), लेकिन एक स्तर पर मैं इस कोशिश की:

// If it exists, the free function is defined as 
// bool AFreeFunction(); 
typedef struct { char } undefined; 
template<typename T = void> 
undefined AFreeFunction(); 

template<bool B> 
bool AFreeFunctionWrapper_() { 
    return false; 
} 

template<> 
bool AFreeFunctionWrapper_<false>() { 
    return AFreeFunction(); 
} 

bool AFreeFunctionWrapper() { 
    return AFreeFunctionWrapper_<decltype(AFreeFunction()) == decltype(undefined)>(); 
} 

मुझे अंततः जीसीसी 4.6 के साथ काम करने वाली इस रणनीति का एक रूप मिला, लेकिन फिर पता चला कि 2012 आरसी में भी एमएसवीसी में टेम्पलेट कार्यों के लिए डिफ़ॉल्ट टेम्पलेट तर्कों की अनुमति नहीं है। तो अंतिम समाधान इस तरह दिखता है:

class AFreeFunction { 
public: 
    operator bool() { return false; } 
}; 

यदि फ़ंक्शन परिभाषित किया गया है, तो इसे कॉल किया जाता है। यदि ऐसा नहीं है, तो इसे कक्षा के लिए एक निर्माता के रूप में व्याख्या किया जाता है, जिसे तत्काल bool पर डाला जाता है।

+0

ध्यान दें कि ऊपर दिए गए मुक्त फ़ंक्शन फॉर्म को आंशिक विशेषज्ञता के साथ हल नहीं किया जा सकता है; इसे अनुमति देने के लिए इसे कक्षा टेम्पलेट के रूप में सुधारने की आवश्यकता है। – Tom

+0

नहीं, इसे कक्षा टेम्पलेट होने की आवश्यकता नहीं है, यह * अधिभारित * फ़ंक्शन टेम्पलेट का एक साधारण सेट हो सकता है। –

+0

@ एनएम। अच्छी बात। – Tom

उत्तर

8

आप आमतौर पर टैग प्रेषण के माध्यम से इस समस्या को हल करते हैं। साथ ही, आपके पास पहले से ही t और u - T& और U& का "घोषित प्रकार" है। समानता के प्रकारों की तुलना करने के लिए, आप std::is_same का उपयोग कर सकते हैं। हालांकि, अधिभार संकल्प पहले से ही आप के लिए इस समस्या का हल:

template<class T> 
void f(T& v1, T& v2){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u){ ... } // #2 

# 1 # 2 की तुलना में अधिक विशिष्ट है अगर f को दोनों बहस एक ही प्रकार के कर रहे हैं।

#include <type_traits> 

namespace detail{ 
template<class T, class U> 
void f(T& t, U& u, std::true_type){ ... } // #1 

template<class T, class U> 
void f(T& t, U& u, std::false_type){ ... } // #2 
} // detail:: 

template<class T, class U> 
void f(T& t, U& u){ 
    detail::f(t, u, std::is_same<T,U>()); // tag dispatching 
} 

std::is_samestd::false_type से अगर करता है, तो दोनों प्रकार के एक ही हैं std::true_type से निकाले जाते हैं जाएगा, और: यदि आप किसी भी कारण से, मैनुअल प्रकार तुलना के माध्यम से इस को हल करने पर जोर देते हैं, तो यहां उसे पहले उल्लेख अंक लागू करने के इस तरह दिखाई देंगे नहीं।

+0

क्या कंपाइलर हमेशा बनाए गए सच्चे/झूठे प्रकार को खत्म करता है? मैं एक 'बूल' पर एक टेम्पलेट विशेष कर दिया होगा और इसके बजाय प्रकार में पारित किया होगा। इस तरह, कोई संभावना नहीं है कि एक बेकार प्रकार बनाया गया है। – KitsuneYMG

+0

मुझे यह मिल गया, और सोचा कि शायद यह जवाब क्या होगा, लेकिन उस पर अन्य विचारों को हासिल करने की कोशिश कर रहा था। वास्तविक संदर्भ यह था कि मैं 'टेम्पलेट बूल फ़ंक्शन() {...} 'और' टेम्पलेट <> बूल फ़ंक्शन () {...}' बनाने की कोशिश कर रहा था, फिर इसे 'bool b = function के रूप में तुरंत चालू करें (); '। मैं इस विवरण को प्रश्न में जोड़ सकता हूं। – Tom

4

यह क्यों अमान्य है? decltype का परिणाम, ठीक है, एक प्रकार है। तो यह कुछ कह रहा है

if (int == int) 

जो भाषा स्पष्ट रूप से अनुमति नहीं देती है।

आपको फ़ंक्शन के दो हिस्सों को अलग करने और विशेष भाग को एक विशेष कक्षा में फ़ंक्शन के अंदर रखने की आवश्यकता होगी, और वहां कॉल को अग्रेषित करें। यह पीड़ादायक है।

या, आप typeid या रन-टाइम प्रकार की जानकारी का उपयोग कर सकते हैं, यदि आपका कार्यान्वयन इसे सही तरीके से कार्यान्वित करता है, हालांकि यह प्रोग्राम चलाने के दौरान सब कुछ स्थगित कर देगा (जो कम अनुकूलन के लिए अनुमति देता है)।

+0

शायद मैं सवाल को अधिक सरल बना दिया। मुझे लगता है कि 'अगर (int == int) 'मान्य नहीं है। यह मेरे लिए कम स्पष्ट है कि क्यों 'some_template ' मान्य नहीं है। 'Some_template ' - पूरी तरह से मान्य, और 'decltype' के समानता पर विचार करें 'sizeof' का प्राकृतिक विस्तार होना चाहिए। – Tom

+0

@ टॉम: 'sizeof' एक * मान * देता है। 'decltype'" रिटर्न "एक * प्रकार *। वे अलग जानवर हैं .. – Mehrdad

+1

काफी सच नहीं है। 'sizeof' एक _constant_ मान देता है जो संकलक समय पर टेम्पलेट त्वरण को हल करने के लिए संकलक को सक्षम बनाता है। मेरा सवाल यह था कि मानक समिति ने प्रकारों की संकलन-समय की तुलना की अनुमति क्यों नहीं दी क्योंकि वे प्रकारों के संकलन-समय की तुलना की अनुमति देते हैं। – Tom

3

आप SFINAE (std::enable_if) का उपयोग कर सकते हैं:

template<typename T, typename U> 
typename std::enable_if<std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "same\n"; 
} 
template<typename T, typename U> 
typename std::enable_if<!std::is_same<T, U>::value, void>::type func(T& t, U& u) { 
    std::cout << "different\n"; 
} 

Mehrdad कहते हैं, decltype(t) और decltype(u) (क्रमशः T & और U &) प्रकार के होते हैं के रूप में, मूल्यों नहीं है, इसलिए मूल्य अभिव्यक्ति के स्तर पर तुलना नहीं की जा सकती है, लेकिन मेटा-एक्सप्रेशन (टेम्पलेट) स्तर पर तुलना की जानी चाहिए।

+0

मुझे लगता है कि यह कैसे काम करता है; सिर्फ यह सोचकर कि क्या एक अच्छा कारण है कि मानकों समिति ने 'decltype' के परिणाम की तुलना की अनुमति नहीं दी है। मैं जो हासिल करने की कोशिश कर रहा था उसके लिए संपादित प्रश्न देखें; वास्तव में तुलना एक टेम्पलेट तर्क संदर्भ में हो रही थी, और जो भी आप सुझाव देते हैं उसके काफी करीब है। मैं वास्तव में 'std :: enable_if' के बारे में नहीं जानता था और' std :: is_same' के बारे में नहीं सुना था। – Tom

+0

@Tom 'decltype' एक फ़ंक्शन नहीं है, यह एक ऑपरेटर है, इसलिए इसका" परिणाम "किसी मान की तरह व्यवहार नहीं करना है। – ecatmur

+0

मुझे यकीन नहीं है कि मैं उस तर्क का पालन करता हूं। हर दूसरे ऑपरेटर का नतीजा एक मूल्य की तरह व्यवहार करता है। 'sizeof' एक बहुत करीबी से संबंधित ऑपरेटर है जो कुछ ऐसा मानता है जो किसी मान की तरह व्यवहार करता है लेकिन तुलनात्मक समय पर अन्य (निरंतर) मानों की तुलना में तुलना की जा सकती है, जिस तरह से मैं (गलत तरीके से) अपेक्षित' decltype' करने की अपेक्षा करता हूं। – Tom

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