फ़ंक्शन प्रकार के तर्क के लिए टेम्पलेट तर्क कटौती


10

निम्नलिखित कार्यक्रम पर विचार करें।

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void g( int x )
{
    std::cout << "g( " << x << " );\n";
}

int main()
{
    f( g );
}

कार्यक्रम सफलतापूर्वक संकलित है और इसका आउटपुट है

g( 42 );

अब गैर टेम्पलेट समारोह का नाम बदलने के जाने gके लिए f

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void f( int x )
{
    std::cout << "f( " << x << " );\n"; 
}

int main()
{
    f( f );
}

अब प्रोग्राम gcc HEAD 10.0.0 20200 और क्लैंग HEAD 10.0.0 द्वारा संकलित नहीं किया गया है, लेकिन विजुअल C ++ +9 ।।

उदाहरण के लिए कंपाइलर gcc संदेशों के निम्नलिखित सेट को जारी करता है।

prog.cc: In function 'int main()':
prog.cc:22:10: error: no matching function for call to 'f(<unresolved overloaded function type>)'
   22 |     f( f );
      |          ^
prog.cc:4:6: note: candidate: 'template<class T> void f(void (*)(T))'
    4 | void f( void ( *fn )( T ) )
      |      ^
prog.cc:4:6: note:   template argument deduction/substitution failed:
prog.cc:22:10: note:   couldn't deduce template parameter 'T'
   22 |     f( f );
      |          ^
prog.cc:14:6: note: candidate: 'void f(int)'
   14 | void f( int x )
      |      ^
prog.cc:14:13: note:   no known conversion for argument 1 from '<unresolved overloaded function type>' to 'int'
   14 | void f( int x )
      |         ~~~~^

तो एक सवाल उठता है: क्या कोड को संकलित किया जाना चाहिए और क्या कारण है कि कोड को gcc और clang द्वारा संकलित नहीं किया गया है?



नोट: पहले उदाहरण में, फंक्शन टेम्प्लेट में जाने g(के बजाय &g) एक प्रकार के क्षय का कारण बनता है (एक फंक्शन के लिए पॉइंटर को रेवल्यू रेफरेंस डिसेबल करता है: void(&)(T)=> void(*)(T))। यह अंतर्निहित रूपांतरण इसलिए होता है क्योंकि fबेहतर मैच के साथ कोई अन्य अधिभार नहीं होता है । दूसरे उदाहरण में, एक अस्पष्टता है जिसे fआप वास्तव में कॉल करना चाहते हैं क्योंकि ... यह नहीं जानता कि कौन सा fतर्क है।
Xeverous

जवाबों:


7

यह मुझे प्रतीत होगा कि gcc और clang सही हैं। यह संकलन नहीं करना चाहिए। जिस फ़ंक्शन पैरामीटर से आप कटौती करना चाहते हैं, Tवह एक गैर-कटौती किए गए संदर्भ बन जाता है, जिस समय आपूर्ति की गई तर्क एक अधिभार सेट है जिसमें एक फ़ंक्शन टेम्पलेट शामिल है [temp.deduct.type ]/5.5 :

गैर-कटौती किए गए संदर्भ हैं:

  • [...]
  • एक फ़ंक्शन पैरामीटर जिसके लिए तर्क में कटौती नहीं की जा सकती है क्योंकि संबद्ध फ़ंक्शन तर्क एक फ़ंक्शन है, या ओवरलोड कार्यों का एक सेट ([ओवरओवर]), और निम्न में से एक या अधिक लागू होता है:

    • [...]
    • एक तर्क के रूप में दिए गए कार्यों के सेट में एक या अधिक फ़ंक्शन टेम्पलेट शामिल हैं।
  • [...]

इस प्रकार, Tकाटा नहीं जा सकता है और कोई रूपांतरण नहीं होने के कारण अन्य अधिभार व्यवहार्य नहीं है; बिल्कुल क्या जीसीसी कहता है ...


0

ये दो अतिभारित कार्य हैं और गैर-टेम्पलेट फ़ंक्शन को टेम्पर्ड फ़ंक्शन की तुलना में चुना जाना चाहिए, इसलिए f (int x) का चयन किया गया था इसलिए फ़ंक्शन में एक तर्क के रूप में एक फ़ंक्शन पास करना जो int पारित किया जाना असंभव है। और नीचे काम करना चाहिए। धन्यवाद

void f( void ( *fn )( int ) ){
  fn( 42 );
}
void f( int x ){
    std::cout << "f( " << x << " );\n";
  }

  int main(){

     f( f );
  }

गैर-टेम्पलेट फ़ंक्शंस केवल तभी पसंद की जाती हैं जब ओवरलोड रिज़ॉल्यूशन के दौरान एक टाई हो। प्रश्न का कोड उस बिंदु पर नहीं आता है: किसी भी स्तर void f<int>(void(int))पर अधिभार संकल्प करने के लिए उत्पन्न कोई विशेषज्ञता कभी नहीं होती है ।
डेविस हेरिंग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.