C++17 auto टेम्प्लेट तर्कों के साथ खेलते हुए मुझे एक और g++/clang++ असहमति का सामना करना पड़ा है।

निम्नलिखित सरल कोड को देखते हुए

template <auto>
struct foo;

template <int I>
struct foo<I>
 { };

int main ()
 {
   foo<42l> f42; // <--- long constant, not int constant

   (void)f42; // avoid the "unused variable" warning
 }

मैं देखता हूं कि क्लैंग ++ (8.0.0, उदाहरण के लिए) उस कोड को संकलित करता है जहां g ++ (9.2.0, उदाहरण के लिए) निम्न त्रुटि देता है

prog.cc: In function 'int main()':
prog.cc:12:13: error: aggregate 'foo<42> f42' has incomplete type and cannot be defined
   12 |    foo<42l> f42;
      |             ^~~

यदि हम एक long स्थिरांक के बजाय एक int स्थिरांक का उपयोग करते हैं, तो दोनों संकलक संकलित करते हैं

  foo<42>  f42;  // compile with both clang++ and g++

इसलिए मेरे पास C++ भाषा परतों के लिए दो प्रश्न हैं

(१) यह कानूनी है, सी ++ १७ में, एक विशिष्ट प्रकार के मूल्य के लिए (मेरे कोड में foo विशेषज्ञता के रूप में) एक auto टेम्पलेट पैरामीटर प्राप्त करने वाले घोषित टेम्पलेट को विशेषज्ञ बनाएं?

(२) यदि पिछले प्रश्न का उत्तर "हाँ" है, तो एक टेम्पलेट विशेषज्ञता एक अलग (लेकिन परिवर्तनीय) प्रकार के मूल्य को रोक सकती है?

प्रश्न (2) लगभग है: राइट क्लैंग++ या जी++ है?

11
max66 21 अगस्त 2019, 16:22

1 उत्तर

सबसे बढ़िया उत्तर

यहाँ थोड़ा अलग रेप्रो है जो अधूरे प्रकारों पर निर्भर नहीं करता है:

template <auto> struct foo { static constexpr int value = 0; };
template <int I> struct foo<I> { static constexpr int value = 1; };

// ok on gcc, fires on clang which thinks foo<42L>::value is 1
static_assert(foo<42L>::value == 0);

यह एक क्लैंग बग है। 42L स्पष्ट रूप से auto से मेल खाता है, कोई सवाल नहीं है। लेकिन क्या यह int I से मेल खाता है? नहीं, [temp.deduct.type]/19 से:

यदि P में एक प्रपत्र है जिसमें <i> है, और यदि i का प्रकार संलग्न सरल-टेम्पलेट- द्वारा नामित टेम्पलेट के संगत टेम्पलेट पैरामीटर के प्रकार से भिन्न है- आईडी, कटौती विफल हो जाती है। यदि P में एक प्रपत्र है जिसमें [i] है, और यदि i का प्रकार एक अभिन्न प्रकार नहीं है, तो कटौती विफल हो जाती है। [ उदाहरण:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
  A<1> a;
  f(a);             // error: deduction fails for conversion from int to short
  f<1>(a);          // OK
}


template<const short cs> class B { };
template<short s> void g(B<s>);
void k2() {
  B<1> b;
  g(b);             // OK: cv-qualifiers are ignored on template parameter types
}

अंतिम उदाहरण ]

यह देखने के लिए कि क्या 42L विशेषज्ञता से मेल खाता है, हमें 42L से घटाना int I करना होगा और यह विफल हो जाता है। इसलिए, हम प्राथमिक विशेषज्ञता के साथ चिपके रहते हैं। क्लैंग ऐसा नहीं करता है। फ़ाइल 43076.

7
Barry 21 अगस्त 2019, 17:49