क्लैंग कोड को संकलित नहीं करता है, लेकिन जीसीसी और एमएसएमएक्स ने इसे संकलित किया है


14

मुझे समझ नहीं आ रहा है कि समस्या क्या है: या तो मेरे कोड में या संकलक में (कम संभव)। इस तरह का एक कोड है:

#include <iostream>
#include <type_traits>
#include <set>


template<typename T, typename = void>
struct TestA: std::false_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::reverse_iterator>> : std::true_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::dummy_iterator>> : std::true_type {};

int main()
{
    std::cout << TestA<std::set<int>>::value;
}

GCC और MSVC दोनों इसे संकलित करते हैं। मैंने इसे GCC और MSVC 17 (स्थानीय) और 19 के विभिन्न संस्करण के साथ गॉडबोल्ट पर परीक्षण किया। यहां एक लिंक दिया गया है: https://godbolt.org/z/Enfm6L

लेकिन क्लैंग इसे संकलित नहीं करता है और एक त्रुटि का उत्सर्जन करता है:

redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`

और मुझे दिलचस्पी है - शायद मानक का कुछ हिस्सा है जहां यह कोड गलत है या शायद कुछ और है।


कैसे हैं "std :: सेट :: reverse_iterator" और "std :: सेट :: dummy_iterator" बजना हेडर में परिभाषित किया?
1913 को mvidelgauz

std :: set :: dummy_iterator को क्लैग हेडर में बिल्कुल भी परिभाषित नहीं किया गया है (आई होप)। आप dummy_iterator को अपनी इच्छानुसार किसी भी समय बदल सकते हैं और यह परिणाम को नहीं बदलेगा क्योंकि समस्या परिभाषा में नहीं है जैसा कि नीचे देखा गया है।
आंद्रेई

धन्यवाद आंद्रेई, मैंने जवाब पढ़ा और यह वास्तव में दिलचस्प है
mvidelgauz

जवाबों:


9

यह CWG 1558 से संबंधित है ।

अलियास टेम्पलेट विशेषज्ञता में अप्रयुक्त तर्कों का उपचार 17.6.7 [temp.asas] के वर्तमान शब्दांकन द्वारा निर्दिष्ट नहीं है। उदाहरण के लिए:

  #include <iostream>

  template <class T, class...>
    using first_of = T;

  template <class T>
    first_of<void, typename T::type> f(int)
      { std::cout << "1\n"; }

  template <class T>
    void f(...)
      { std::cout << "2\n"; }

  struct X { typedef void type; };

  int main() {
    f<X>(0);
    f<int>(0);
  }

क्या T के साथ First_of का संदर्भ केवल शून्य के बराबर है, या यह एक प्रतिस्थापन विफलता है?

यह एक दोष है जिसे संबोधित किया गया था, लेकिन यदि आपके द्वारा उपयोग किए गए क्लैंग का संस्करण अभी तक फिक्स को लागू नहीं करता है, तो यह अभी भी दोनों विशेषज्ञता को दूसरे तर्क को परिभाषित करने के रूप में मान सकता है void, और पूरे प्रतिस्थापन विफलता क्षेत्र में नहीं। वर्कअराउंड एक सादे उपनाम का उपयोग नहीं करना है std::void_t, लेकिन इसके बजाय थोड़ा अधिक जटिल संस्करण है

template <typename...> struct voider { using type = void; };
template <typename... T> using my_void_t = typename voider<T...>::type;

एक क्लास टेम्पलेट के लिए (जो कि अब उर्फ ​​खड़ा है), प्रतिस्थापन विफलता को परिभाषित किया गया है। प्लग इन करना आपके उदाहरण में Clang https://godbolt.org/z/VnkwsM को प्रदर्शित करता है


1
प्रत्येक आवश्यकता के लिए लक्षण बनाने के लिए एक और समाधान होगा, और फिर उन्हें एक (या एक क्लॉज़ की आवश्यकता) के enable_ifसाथ संयोजित करेंstd::disjunction
एंडीजी

मदद और संदर्भ के लिए धन्यवाद! क्लैंग में इस तरह की बग के बारे में सुनकर दुख हुआ। हालांकि, मजेदार, मैंने सोचा कि आपका void_t का कार्यान्वयन मानक है। टेम्पलेट एलियासिंग के विचार को नहीं अपना सकते।
आंद्रेई
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.