विभिन्न कंपाइलरों के साथ VoidT का उपयोग करने वाला SFINAE अलग परिणाम देता है


10

निम्नलिखित कोड पर विचार करें:

template <typename T> using VoidT = void;

class A {
public:
   using TEST = int;
};

class C {
public:
   using DIFFERENT = int;
};

template <typename T, typename Enable = void>
class B {
public:
   B() = delete;
};

template <typename T>
class B<T, VoidT<typename T::TEST>> {
public:
   B() = default;
};

template <typename T>
class B<T, VoidT<typename T::DIFFERENT>> {
public:
   B() = default;
};

int main() {
   B<A> a;
   B<C> b;

   return 0;
}

G ++ - 4.8.5 का उपयोग करते हुए, इस कोड को संकलित करने से मुझे निम्नलिखित त्रुटि संदेश मिलता है:

~/test/compile_test> g++ -std=c++11 test.cpp

test.cpp:31:7: error: redefinition of ‘class B<T, void>’

test.cpp:24:7: error: previous definition of ‘class B<T, void>’

हालाँकि, जब मैं g ++ - 8.3 (जैसे, उदाहरण के लिए, ideone) का उपयोग करके संकलन करता हूं, तो कोड संकलित होता है और विभिन्न विशेषज्ञताओं का सही तरीके से इलाज किया जाता है। क्या यह जीसीसी में एक बग था, जिसे ठीक किया गया था, या क्या मैं किसी तरह अपरिभाषित व्यवहार का आह्वान कर रहा हूं (और इसलिए संकलक व्यवहार में अंतर एक मूक बिंदु है - यह अपरिभाषित है)?

जवाबों:


9

क्या यह जीसीसी में एक बग था जो तय हो गया था?

यह मानक में एक दोष था। यह पिछले मानक संस्करणों के लिए पूर्वव्यापी रूप से तय किया गया था, लेकिन निश्चित रूप से केवल नए संकलक संस्करणों में ही सुधार होगा। यह सीडब्ल्यूजी अंक 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 का संदर्भ केवल शून्य के बराबर है, या यह एक प्रतिस्थापन विफलता है?

DR फिक्स के बिना कंपाइलर्स के लिए हेल्पर का उपयोग करना है:

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

एक वर्ग टेम्पलेट में प्रतिस्थापन विफलता की गारंटी है।


1
पूर्वव्यापी सुधार मुझे परेशान करते हैं। इसका मतलब है कि भाषा के किसी भी संस्करण का वर्णन करने वाला एक विहित दस्तावेज़ कभी नहीं होता है।
ऑर्बिट

2
@LightnessRacesinOrbit - मैं आपकी बात देखता हूं। कोई उम्मीद कर सकता है कि इस तरह के पूर्वव्यापी सुधार केवल वैध निर्माणों के लिए आरक्षित हैं जिन्हें अस्वीकार नहीं किया जाना चाहिए, इसलिए नुकसान न्यूनतम है।
स्टोरीटेलर - अनसलैंडर मोनिका

@StoryTeller वास्तव में।
को ऑर्बिट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.