क्लास स्पेशलाइजेशन में क्लैंग / जीसीसी असंगति


9

मैं इस मुद्दे पर आया था, जबकि विशेषज्ञ करने की कोशिश कर रहा था tuple_size/tuple_elementसंरचित बाइंडिंग के लिए C ++ 17 में कस्टम क्लास के लिए ।

नीचे कोड जीसीसी में संकलित है, लेकिन क्लैंग में नहीं (दोनों ट्रंक संस्करण, नीचे लिंक देखें)।

#include <type_traits>

template<typename T, typename... Ts>
using sfinae_t = T;

template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;

template <typename T>
struct Test;

template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};

void f() {
    Test<int> t;
}

https://godbolt.org/z/ztuRSq

यह क्लैंग द्वारा प्रदान की गई त्रुटि है:

<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};

       ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

Compiler returned: 1

यह या तो संकलक में एक बग है या उपरोक्त कोड कुछ यूबी को आमंत्रित करता है?


3
इसे और भी सरल बनाया जा सकता है ।
शाम

3
ICC और MSVC दोनों ही संकलन करने में विफल हैं।
क्रिसमम

@Evg यह आश्चर्य की बात है कि gcccompiles कि, यह के रूप में देख रहा है संकलन नहीं है यह ...
मैक्स Langhof

1
अगर मुझे पूरी तरह से गलत नहीं किया गया है (इसी कारण से यह बीमार है) तो एफडब्ल्यूआईडब्ल्यू को बीमार होना चाहिए ।
मैक्स लैंगहॉफ

1
जब से हम मानक उद्धृत कर रहे हैं, मैंने भाषा-वकील टैग जोड़ा।
गिलियूम रैसिकोट

जवाबों:


3

जो मैं नीचे ( OLD POST के तहत ) बताता हूं , वह एक हद तक सही होना चाहिए, लेकिन इसके साथ वास्तविक समस्या यह है कि SFINAE का गलत तरीके से उपयोग किया जाता है, इसलिए मुझे अब यकीन नहीं है कि यह gcc में बग है।

एक अन्य घोषणा हमेशा सफल होनी चाहिए, आप वहां SFINAE नहीं कर सकते हैं, क्योंकि यह एक वर्ग या फ़ंक्शन घोषणा या विशेषज्ञता नहीं है (जो समझ में आता है, क्योंकि आप उपनाम नहीं कर सकते हैं)। यदि उर्फ ​​घोषणा सफल नहीं होती है, तो प्रोग्राम बीमार है। इसलिए कंपाइलर यह मान सकता है कि यह इस मामले में कभी नहीं आएगा कि जब तक आप इस तरह के टेम्पलेट को तुरंत लागू करने के लिए मजबूर नहीं करते हैं तब तक उर्फ ​​घोषणा सफल नहीं होती है।

इसलिए यह संकलक के लिए पूरी तरह से स्वीकार्य है कि sfinae_v_t<T,...>वह हमेशा सोचता हैT , क्योंकि ऐसा तब होगा, जब प्रोग्राम बीमार नहीं है। इसलिए यह देखा जाएगा, कि सभी मामलों में, जिसमें प्रोग्राम बीमार नहीं है, आंशिक विशेषज्ञता विशेषज्ञ नहीं है और जैसे कि यह आपको बताएगा कि यह बीमार है। (वह है जो क्लैंग करता है)।

मुझे नहीं लगता कि संकलक ऐसा करने के लिए मजबूर है। और अगर ऐसा नहीं होता है, और बस सोचता है "ठीक है, sfinae_v_tकुछ प्रकार है, जो भी है।", तो यह स्पष्ट नहीं है कि यह एक पुनर्वितरण है। इसलिए मुझे लगता है कि जब तक हम उनमें से एक को तुरंत नहीं हटा देते हैं, तब तक कोई त्रुटि नहीं है।

लेकिन जब हम इसे तुरंत करते हैं तो या तो समस्या होनी चाहिए कि हमारे पास एक पुनर्वितरण है या यह कि std::enable_ifटेम्पलेट तर्क के आधार पर कार्यक्रम के कारण बीमार है। जीसीसी को उनमें से कम से कम एक को चुनना चाहिए लेकिन न तो।

यह भी पूरी तरह से बिना अधिक आसान उदाहरण के लागू नहीं होता है std::enable_if। इसलिए मुझे अभी भी लगता है कि यह जीसीसी में एक बग है, लेकिन मैं पर्याप्त रूप से दिमाग लगा रहा हूं कि अब मैं निश्चितता के साथ नहीं कह सकता। मैं सिर्फ इतना कहूंगा, किसी को यह बतलाना चाहिए कि बग के रूप में और gcc के लोगों को इसके बारे में सोचने दें।

पुराने पोस्ट

यह gcc में एक बग है। मानक हमें फ़ंक्शन टेम्प्लेट में एक क्लास टेम्पलेट को परिवर्तित करने के लिए नियम देता है । एक फ़ंक्शन टेम्पलेट दूसरे की तुलना में अधिक विशिष्ट है यदि इसका फ़ंक्शन आंशिक फ़ंक्शन टेम्पलेट ऑर्डर में दूसरे के पहले आता है।

मैंने यहां फंक्शन्स बनाए और अब यह दावा किया है कि उन्हें कॉल करना अस्पष्ट है, इसलिए यह भी कहना होगा कि क्लास टेम्पलेट समान रूप से निर्दिष्ट हैं।

नोट: मानक को ध्यान से पढ़ने पर, मेरे सिर में संकलक क्लैंग से सहमत है।


कर रहे हैं sfinae_v_t<T, std::is_integral_v<T>>और sfinae_v_t<T, !std::is_integral_v<T>>एक ही प्रकार के रूप में इलाज? शब्दार्थ, वे नहीं हैं।
इनो

@GuillaumeRacicot काफी संभवतः, लेकिन मैं समझना चाहूंगा कि वास्तव में क्यों। उदाहरण के लिए मानक यह भी कहता है "आंशिक विशेषज्ञता की घोषणा करते समय आश्रित नामों की जाँच नहीं की जा सकती है, लेकिन आंशिक विशेषज्ञता में प्रतिस्थापित करते समय जाँच की जाएगी।" क्या इसका मतलब यह नहीं है कि वे आंशिक विशेषज्ञता में टी को प्रतिस्थापित करने के बाद एक ही प्रकार का फैसला किया जाना है या नहीं, इस sfinae_v_t<T>पर निर्भर है T? किस स्थिति में, वे समान नहीं होंगे क्योंकि या तो कोई बीमार होगा।
इनो

@ मुझे कहना होगा, मुझे यकीन नहीं है। यह उन दोनों के बारे में भी सोचने के लिए एक माइंडफुक है, क्योंकि उनमें से एक कभी भी एक प्रकार नहीं होगा और उन दोनों को गैर-टेम्पलेट संदर्भ में उपयोग करने के परिणामस्वरूप एक संकलन त्रुटि हो जाएगी enable_if_t। मानक के बारे में मेरा सबसे अच्छा पढ़ा है, कि इससे कोई फर्क नहीं पड़ता कि वे समान हैं या नहीं। आंशिक आदेश के लिए हम हमेशा एक फ़ंक्शन के टेम्प्लेयर पैरामीटर फॉर्म की तुलना दूसरे के टेम्प्लेट लॉजिक फॉर्म में करते हैं (अर्थात intपहले से ही प्रतिस्थापित है) और फिर उनमें से एक में एक वास्तविक प्रकार है, इसलिए हमें तुलना नहीं करनी है उन्हें सार।
n314159

1
गहरी खुदाई करते हुए, मुझे यह यहाँ से मिला । SFINAE को टेम्पलेट उपनाम के साथ ठीक काम करना चाहिए, अन्यथा template<bool B, typename T> enable_if_t = typename enable_if<B, T>::type;काम नहीं करेगा। मैं आगे जाऊंगा और gcc के खिलाफ बग दर्ज करूंगा, लेकिन वास्तव में निश्चित नहीं कि अगर gcc वहां गलत है। धन्यवाद।
ofo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.