2015-10-07 12 views
12

this question का जवाब देने के लिए एक वैरैडिक फ़ॉरवर्डिंग संदर्भ कन्स्ट्रक्टर बनाने की कोशिश करने के बारे में, जिसे केवल कोई अन्य कन्स्ट्रक्टर वैध नहीं माना जाना चाहिए। यही कारण है, अगर वहाँ था एक:फ़ॉलबैक वैरिएडिक कन्स्ट्रक्टर - यह क्यों काम करता है?

C(const char*, size_t) { }      // 1 
template <typename... T, ???> C(T&&...) { } // 2 

हम C c1{"abc", 2};, (1) फोन करने के लिए आवश्यक रूपांतरण के बावजूद चाहते हैं, लेकिन C c2{1, 2, 3};, (2) कॉल करने के लिए के रूप में (1) लागू नहीं कर सकते।

मैं निम्नलिखित समाधान का प्रस्ताव:

template <typename... T, 
      typename = std::enable_if_t<!std::is_constructible<C, T&&...>::value> 
      > 
C(T&&...) { } 

और प्रस्तावित द्वारा, मेरा मतलब है, मैं इसे करने की कोशिश की और कहा कि यह वास्तव में काम करता है खोजने के लिए आश्चर्य हुआ। यह संकलित करता है और वही करता है जो मैंने जीसीसी और क्लैंग दोनों के लिए आशा की थी। हालांकि, मुझे की व्याख्या करने के लिए नुकसान हुआ है क्यों यह काम करता है या भले ही यह वास्तव में पर काम करता है और जीसीसी और क्लैंग दोनों ही विशेष रूप से समायोजित होते हैं। क्या यह? क्यूं कर?

+0

मेरी समझ के आधार पर यदि कोई अन्य कन्स्ट्रक्टर 'सी सी 1 {" एबीसी ", 2} के लिए उपलब्ध है;' std :: enable_if_t' की तुलना में कोई मूल्य नहीं होगा, और इसलिए 'टेम्पलेट 'और SFINAE टेम्पलेट कन्स्ट्रक्टर नहीं बनाएगा। –

+1

आपके उत्तर पर मेरी टिप्पणी दोबारा पोस्ट करना: [यह संशोधित उदाहरण] (http://melpon.org/wandbox/permlink/JM2U8pxxvguewhd1) दिखाता है कि डिफ़ॉल्ट तर्क SFINAE * सी * के सभी * कन्स्ट्रक्टर को मानता है, यहां तक ​​कि जिन्हें बाद में घोषित किया जाता है कन्स्ट्रक्टर टेम्पलेट। – dyp

+0

इसके लिए कितना कम मूल्य है, एमएसवीसी 2013 भी इस वाक्यविन्यास को/डब्ल्यू 4 के तहत स्वीकार करता है और जीसीसी के रूप में वही चीज प्रिंट करता है [इस उदाहरण] (http://coliru.stacked-crooked.com/a/1fe984a4ceb6e193), हालांकि यह * करता है * कई डिफ़ॉल्ट रचनाकारों के बारे में चेतावनी देता है, और इंटेलिजेंस ऐसा नहीं लगता है कि 'Foo :: Foo' पर तीसरा कॉल मान्य है। (फिर से, यह वीसी ++ 18 के ठीक होने के बावजूद है) – jaggedSpire

उत्तर

10

आपके कोड के साथ समस्या यह है कि हमने को संदर्भ में तुरंत संदर्भित किया है जहां यह उत्तर गलत है। टेम्पलेट कोड में किसी भी प्रकार की कैशिंग के परिणामस्वरूप बग्स हो सकते हैं - कन्स्ट्रक्टर को कॉल करने के बाद उसी पैरामीटर पर is_constructible प्रिंट करने का प्रयास करें! यह गलत होने की संभावना है।

Live example यह गलत कैसे हो सकता है। ध्यान दें कि पिछली लाइन पर ऐसा करने के बावजूद int& से C का निर्माण नहीं किया जा सकता है।

struct C { 
    C(const char*, size_t) {} 
    template <class... Ts, 
    typename = std::enable_if_t<!std::is_constructible<C, Ts&&...>::value> 
    > 
    C(Ts&&...) { } 
}; 

int main() { 
    int a = 0; 
    C x{a}; 
    std::cout << std::is_constructible<C, int&>{} << '\n'; 
} 

ओह।

मुझे संदेह है कि यह ओडीआर उल्लंघन हो सकता है - is_constructible की दो परिभाषाओं के विभिन्न स्थानों पर विभिन्न प्रकार हैं? या शायद नहीं।

Solution to the original problem that does not have this issue भी पोस्ट किया गया।

+0

@dyp संभवतः। मैं बस यह इंगित कर रहा था कि प्रस्तुत समाधान वास्तव में काम नहीं करता है। मुझे लगता है कि मैं चला गया और मूल समस्या हल भी। ;) ठीक है, इसे दो भागों में विभाजित करें। – Yakk

+0

मानक टेम्पलेट डिफ़ॉल्ट-तर्कों के तत्कालता के बिंदु को निर्दिष्ट करता है? T.C. ऐसा लगता है कि ओपी को टिप्पणियों में यह बताया गया है कि यह अनिर्धारित है .. – dyp

+0

@dyp निश्चित रूप से, मुझे विश्वास है कि कई चीजें मानक में निर्दिष्ट हैं। तो या तो यह काम नहीं करता है (क्योंकि यह खुद को देखने के लिए देर से तत्काल है?), या यह काम करता है (और दुनिया को तोड़ता है, क्योंकि यह गलत जवाब देता है)? मेरा मुद्दा यह है कि गलत जवाब पाने के लिए 'is_constructible' पर निर्भर समाधान नहीं है, लेकिन समाधान की नींव में छिपी हुई समस्या है। – Yakk

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