2013-06-03 9 views
11

कैसे निर्धारित करें (<type_traits> भावना में) चाहे एक प्रकार स्पष्ट रूप से दूसरे प्रकार में परिवर्तनीय हो या नहीं? उदाहरण के लिए, मैं कुछ class/structF के लिए F::explicit operator double const &() const; की उपस्थिति की जांच करना चाहते हैं, लेकिन एक ही समय में, F नहीं स्पष्ट रूप से परिवर्तनीय को float या long double (कुछ pred< double const & >::value && !pred<float>::value && !pred< long double >::value) की तरह किया गया चाहिए।जांचें कि किस प्रकार प्रकार को स्पष्ट रूप से परिवर्तित किया जा सकता है

ध्यान दें, कि std::is_convertible< From, To >::value चेकों "अगर से अंतर्निहित रूपांतरण का उपयोग कर करने के लिए में बदला जा सकता"। लेकिन मैं यह निर्धारित करना चाहता हूं कि स्पष्ट रूपांतरण ऑपरेटर है या नहीं।

और, अगर यह संभव, "कैसे निर्धारित करने के लिए, टाइप करें से एक अर्थात् संदर्भ में परिवर्तनीय टाइप करने के लिए करने के लिए है?"?

+0

शायद मैं इस सवाल को गलत समझ रहा हूं, लेकिन आप 'dynamic_cast (FROM & val)' कर सकते हैं, यदि रूपांतरण योग्य नहीं है तो यह 'std :: bad_cast' फेंक देगा। –

+0

@ एच 2CO3 मान लीजिए, यह प्रश्न संकलन समय के मुद्दे के बारे में है। – Orient

+2

जैसा कि आप एक स्पष्ट रूपांतरण ऑपरेटर की जांच करना चाहते हैं, आपका कार्य नीचे उबालता प्रतीत होता है [यह निर्धारित करना कि कक्षा टी के पास दिए गए हस्ताक्षर के साथ सदस्य कार्य है या नहीं) (http://stackoverflow.com/q/87372/1362568)। मेरे कई में से कई उत्तर हैं। –

उत्तर

11

आप परिभाषित करने की जरूरत अपनी खुद की:

template <class U, class T> 
struct is_explicitly_convertible 
{  
    enum {value = std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value}; 
}; 
7

आपका परीक्षण सेट एक ऑफ साइट लिंक पर है और अपने मूल पोस्ट के बाद से विविध है, इसलिए मैं शब्दशः परीक्षण सेट के बारे में मैं बात कर रहा हूँ की प्रतिलिपि बनाएगा यहाँ:

:

static_assert(is_explicitly_convertible< double, double >::value, "1"); 
static_assert(is_explicitly_convertible< double &, double >::value, "2"); 
static_assert(is_explicitly_convertible< double const, double >::value, "3"); 
static_assert(is_explicitly_convertible< double const &, double >::value, "4"); 

static_assert(is_explicitly_convertible< double, double const & >::value, "5"); 
static_assert(is_explicitly_convertible< double &, double const & >::value, "6"); 
static_assert(is_explicitly_convertible< double const, double const & >::value, "7"); 
static_assert(is_explicitly_convertible< double const &, double const & >::value, "8"); 

static_assert(!is_explicitly_convertible< double, double & >::value, "9"); // not a ref 
static_assert(is_explicitly_convertible< double &, double & >::value, "10"); 
static_assert(!is_explicitly_convertible< double const, double & >::value, "11"); 
static_assert(!is_explicitly_convertible< double const &, double & >::value, "12"); 

static_assert(is_explicitly_convertible< double, double const >::value, "13"); 
static_assert(is_explicitly_convertible< double &, double const >::value, "14"); 
static_assert(is_explicitly_convertible< double const, double const >::value, "15"); 
static_assert(is_explicitly_convertible< double const &, double const >::value, "16"); 

static_assert(is_explicitly_convertible< AA const &, A const & >::value, "=&1.a"); 
static_assert(is_explicitly_convertible< CC const &, C const & >::value, "=&1.b"); 
static_assert(is_explicitly_convertible< BB const &, B const & >::value, "=&1.c"); 
static_assert(!is_explicitly_convertible< AA const &, A & >::value, "&1.a"); 
static_assert(!is_explicitly_convertible< CC const &, C & >::value, "&1.b"); 
static_assert(!is_explicitly_convertible< BB const &, B & >::value, "&1.c"); 

static_assert(is_explicitly_convertible< AA const, A const & >::value, "=1.a"); 
static_assert(is_explicitly_convertible< CC const, C const & >::value, "=1.b"); 
static_assert(is_explicitly_convertible< BB const, B const & >::value, "=1.c"); 
//static_assert(!is_explicitly_convertible< AA const, A >::value, "=2.a"); // ??????????????? 
//static_assert(!is_explicitly_convertible< CC const, C >::value, "=2.b"); 
//static_assert(!is_explicitly_convertible< BB const, B >::value, "=2.c"); 
static_assert(!is_explicitly_convertible< AA const, A & >::value, "=3.a"); // good! 
static_assert(!is_explicitly_convertible< CC const, C & >::value, "=3.b"); // 
static_assert(!is_explicitly_convertible< BB const, B & >::value, "=3.c"); // 
static_assert(!is_explicitly_convertible< AA const, A && >::value, "=4.a"); // not interesting 
static_assert(!is_explicitly_convertible< CC const, C && >::value, "=4.b"); // 
static_assert(!is_explicitly_convertible< BB const, B && >::value, "=4.c"); // 
static_assert(!is_explicitly_convertible< AA const, B const & >::value, "=5.a"); 
static_assert(!is_explicitly_convertible< AA const, C const & >::value, "=5.b"); 
static_assert(!is_explicitly_convertible< BB const, A const & >::value, "=5.c"); 
static_assert(!is_explicitly_convertible< BB const, C const & >::value, "=6.a"); 
static_assert(!is_explicitly_convertible< CC const, A const & >::value, "=6.b"); 
static_assert(!is_explicitly_convertible< CC const, B const & >::value, "=6.c"); 
static_assert(!is_explicitly_convertible< AA const, B & >::value, "=7.a"); 
static_assert(!is_explicitly_convertible< AA const, C & >::value, "=7.b"); 
static_assert(!is_explicitly_convertible< BB const, A & >::value, "=7.c"); 
static_assert(!is_explicitly_convertible< BB const, C & >::value, "=8.a"); 
static_assert(!is_explicitly_convertible< CC const, A & >::value, "=8.b"); 
static_assert(!is_explicitly_convertible< CC const, B & >::value, "=8.c"); 
static_assert(!is_explicitly_convertible< AA const, B >::value, "=9.a"); // very subtle moment (see class AA above) 
static_assert(!is_explicitly_convertible< AA const, C >::value, "=9.b"); 
static_assert(is_explicitly_convertible< BB const, A >::value == std::is_constructible< A, A && >::value, "=9.c"); // (see class BB above) 
static_assert(!is_explicitly_convertible< BB const, C >::value, "=10.a"); 
static_assert(!is_explicitly_convertible< CC const, A >::value, "=10.b"); 
static_assert(!is_explicitly_convertible< CC const, B >::value, "=10.c"); 

static_assert(is_explicitly_convertible< AA, A & >::value, "~1.a"); 
static_assert(is_explicitly_convertible< CC, C & >::value, "~1.b"); 
static_assert(is_explicitly_convertible< BB, B & >::value, "~1.c"); 
//static_assert(!is_explicitly_convertible< AA, A >::value, "~2.a"); // ??????????????? 
//static_assert(!is_explicitly_convertible< CC, C >::value, "~2.b"); 
//static_assert(!is_explicitly_convertible< BB, B >::value, "~2.c"); 
static_assert(is_explicitly_convertible< AA, A const & >::value, "~3.a"); // convertible 
static_assert(is_explicitly_convertible< CC, C const & >::value, "~3.b"); // 
static_assert(is_explicitly_convertible< BB, B const & >::value, "~3.c"); // 
static_assert(!is_explicitly_convertible< AA, B const & >::value, "~4.a"); 
static_assert(!is_explicitly_convertible< AA, C const & >::value, "~4.b"); 
static_assert(!is_explicitly_convertible< BB, A const & >::value, "~4.c"); 
static_assert(!is_explicitly_convertible< BB, C const & >::value, "~5.a"); 
static_assert(!is_explicitly_convertible< CC, A const & >::value, "~5.b"); 
static_assert(!is_explicitly_convertible< CC, B const & >::value, "~5.c"); 

static_assert(std::is_convertible< double, double const & >::value, "5*"); 
static_assert(!std::is_convertible< double, double & >::value, "9*"); 

आप जीसीसी 4.7.2 (और शायद पहले, मैं जांच न की हो) का लाभ उठाने तो सी ++ 11 स्टैंडर्ड लाइब्रेरी समस्या का हल

<type_traits>

हालांकि में परिभाषित किया गया है, तो आप सी ++ 11 स्टैंडर्ड लाइब्रेरी के उस संस्करण में एक error का लाभ उठाने की जाएगी। यह विशेषता टेम्पलेट वहां नहीं होना चाहिए था, क्योंकि इसे N3047 (2010) के अनुसार मानक से हटा दिया गया था।

यदि आप जीसीसी 4.8.1 (या शायद 4.8; मैंने चेक नहीं किया है) पर है तो यह विशेषता लाइब्रेरी में अब नहीं है, और यदि आप चाहते हैं तो आपको फिर से अपना रोल करना होगा।

लेकिन यह केवल एक शुरुआत के लिए जीसीसी 4.7.2 के <type_traits> में परिभाषा का निरीक्षण करने के लिए मानव होगा, और है कि कर पता चलता है कि जीएनयू implementer माना विशेषता लेकिन std::is_constructible<To,From> का प्रतिलोम कुछ भी नहीं होने के लिए:

/// is_explicitly_convertible 
template<typename _From, typename _To> 
struct is_explicitly_convertible 
: public is_constructible<_To, _From> 
{ }; 

कोई भी सोच सकता है: लेकिन ज़ाहिर है।

तो ऐसा क्यों नहीं चल रहा है? एन 3047 बताता है:

शेष प्रश्न यह है कि जिस तरह से is_explicitly_convertible विशेषता भी प्रभावित की जानी चाहिए।बुनियादी विकल्प हैं:

  1. वर्तमान static_cast अभिव्यक्ति की ओर लौटने, अब is_constructible पर is_explicitly_convertible निर्भर बनाकर फिक्स is_explicitly_convertible
  2. मानक से is_explicitly_convertible हटाएं।

पहली पसंद पर विचार किया गया था, लेकिन यह पता चला कि "स्पष्ट रूप से परिवर्तनीय" वास्तव में क्या मतलब होना चाहिए, इसकी काफी अलग-अलग समझ है। जबकि कुछ मानते हैं कि static_cast सही ढंग से इसे व्यक्त करता है, अन्य लोगों का मानना ​​है कि निश्चित is_constructibleis_explicitly_convertible के लिए भी बेहतर अर्थ प्रदान करेगा। इसलिए यह पत्र कार्य ड्राफ्ट से is_explicitly_convertible को हटाने की सिफारिश करता है। इसे अब कोई नुकसान नहीं करना चाहिए, क्योंकि कुछ भी उस विशेष परिभाषा पर निर्भर नहीं है। और यदि यह पता चला है कि यह विशेषता अभी भी उपयोगी होगी, तो इसे मानक के एक और संशोधन में जोड़ा जा सकता है।

कि परिभाषा कोई ज्ञात बग था, लेकिन वहाँ के रूप में है कि क्या की "स्पष्ट रूप से परिवर्तनीय" अर्थ है कि यह codifies सही एक है का विरोध भी दृश्य नहीं थे: -

  • डी 1) From है स्पष्ट रूप से To = df To के लिए परिवर्तनीय From
  • डी 2 से constructible) From स्पष्ट To = df From के लिए परिवर्तनीय स्थिरको ढाला जा सकता है

मैं इस विवाद (मैं भी बाहर काम नहीं किया कि क्या अंतर है, अपने आप को), लेकिन है कि आप बस अपने पैसे का भुगतान और अपनी पसंद ले सुझाव देगा करने के लिए बहस नहीं होगी।

यदि आप डी 1 का पक्ष लेते हैं) तो आप उपरोक्त के रूप में जीसीसी 4.7.2 <type_traits> पर से विशेषता की परिभाषा ले सकते हैं।

यदि आप डी 2 का पक्ष लेते हैं, तो आप gcc 4.8.1 <type_traits> से std::is_convertible<From,To> की परिभाषा को चोरी और अनुकूलित कर सकते हैं। यह परिभाषा आंतरिक सहायक कार्यों को आमंत्रित करती है जिन्हें आपको ट्रैक करना होगा।अनुकूलन आप चाहेगा From के लिए बदलने के लिए From के लिए SFINAE परीक्षण परोक्ष एक परीक्षण करने के लिए To लिए डाली जा सकती है static_castTo हो सकता है हो सकता है; और उस का मतलब होगा की जगह:

साथ
template<typename _From1, typename _To1> 
    static decltype(__test_aux<_To1>(std::declval<_From1>()), __one()) 
__test(int); 

:

template<typename _From1, typename _To1> 
    static decltype(__test_aux<_To1>(static_cast<_To1>(std::declval<_From1>())), __one()) 
__test(int); 

इस परिभाषा के एक कट-डाउन संस्करण ( From के रूप में इस तरह के मामलों की अनदेखी की जा रही void और To एक समारोह या सरणी प्रकार किया जा रहा है), जो आपके static_assert एस में परीक्षण किए गए प्रकारों के लिए करेगा:

template<typename From, typename To> 
struct is_explicitly_convertible 
{ 
    template<typename T> 
    static void f(T); 

    template<typename F, typename T> 
    static constexpr auto test(int) -> 
    decltype(f(static_cast<T>(std::declval<F>())),true) { 
     return true; 
    } 

    template<typename F, typename T> 
    static constexpr auto test(...) -> bool { 
     return false; 
    } 

    static bool const value = test<From,To>(0); 
}; 

या तो डी 1 परिभाषा या कट-डाउन डी 2 परिभाषा आपके सभी static_assert एस के 63 में से एक को बनाए रखती है। (मैं ++ जी के साथ 4.7.2 और 4.8.1, -g;-O0;-Wall;-std=c++11 संकलित, और भी -std=gnu++1y कि आप कार्यरत साथ)

आपका नवीनतम समाधान पता चलता है कि आप एक अलग के साथ डी 2 स्कूल के लिए अपने अपने तरीके से बना दिया है, कार्यान्वयन की शैली।

दो के

, जब तक मैं कुछ इसके साथ गलत लगता है, मैं, डी 1 परिभाषा पसंद करेंगे प्रति जीसीसी 4.7.2 के रूप में है, क्योंकि केवल यह बहुत सरल है और विशेष रूप से std::is_constructible की एक छोटी सी व्युत्पन्न है।

+1

दोनों डी 1) और डी 2) दृष्टिकोण 'std = gnu ++ 1y' विकल्प के साथ अंतिम __gcc__ (mingw-builds 4.8.1 rev0) पर मेरे परीक्षण मामले पर पूरी तरह से बराबर हैं। तो, आखिरकार, मैं डी 1 चुनता हूं), क्योंकि मुझे कुछ भी नया लिखने की आवश्यकता नहीं है। – Orient

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

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