c++ - `Std:: function` के साथ प्रतिस्थापन विफलता और पहले से तैयार टेम्पलेट पैरामीटर-क्यों?




c++11 templates (2)

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

template <typename> 
struct S { };

void g(S<int> t);

template <typename T>
void f(T, std::function<void(S<T>)>);

जब आह्वान करने का प्रयास किया गया

f(0, g);

मुझे निम्नलिखित त्रुटि मिलती है:

error: no matching function for call to 'f'
    f(0, g);
    ^

note: candidate template ignored: could not match 
      'function<void (S<type-parameter-0-0>)>' 
      against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
     ^

Godbolt.org पर लाइव उदाहरण

जबकि मैं समझता हूं कि आम तौर पर std::function पैरामीटर का प्रकार घटाया नहीं जा सकता क्योंकि यह एक गैर-कटौती वाला संदर्भ है

इस स्थिति में T को पहले पास किए गए तर्क 0 घटाया जा सकता है, और फिर std::function<void(S<T>)> को std::function<void(S<int>)> में प्रतिस्थापित किया जाता है।

मुझे उम्मीद है कि T=int बाद, कंपाइलर हस्ताक्षर में हर जगह T को स्थानापन्न करेगा और फिर तर्क g साथ std::function पैरामीटर का निर्माण करने का प्रयास करेगा।

ऐसा क्यों नहीं है? मुझे लगता है कि जिस क्रम में प्रतिस्थापन / कटौती होती है, उसका इस से कुछ लेना-देना है, लेकिन मैं संबंधित मानक शब्दावलियों को देखना चाहूंगा।

बोनस प्रश्न: क्या यह ऐसी चीज है जिसे भविष्य में मानक में बदला जा सकता है जबकि बैकवर्ड संगतता को संरक्षित करते हुए, या क्या कोई मूलभूत कारण है कि इस तरह का प्रतिस्थापन काम नहीं करता है?


जबकि मैं समझता हूं कि आम तौर पर std::function का प्रकार std::function पैरामीटर को घटाया नहीं जा सकता है क्योंकि यह एक गैर-कटौती वाला संदर्भ है, इस मामले में T पहले पारित तर्क 0 द्वारा कटौती की जा सकती है।

यह सच नहीं है। T इस संदर्भ में ध्यान देने योग्य है। यदि आप कोड को बदलते हैं

template <typename T>
void f(std::function<void(S<T>)>);

int main()
{
    f(std::function<void(S<int>)>(g));
}

कोड संकलित होगा और T सही ढंग से घटाया गया है।

आपका मुद्दा यह है कि आप फ़ंक्शन के लिए एक ऑब्जेक्ट पास कर रहे हैं कि यह T से नहीं निकाल सकता है। कंपाइलर फ़ंक्शन तर्कों का कोई भी रूपांतरण नहीं करेगा जब वह T को कम करने की कोशिश करता है। इसका मतलब है कि आपके पास एक int और फ़ंक्शन है जैसा कि फ़ंक्शन को दिया गया है। यह 0 से int हो जाता है, फिर std::function से प्रकार प्राप्त करने की कोशिश करता है std::function आप दूसरे पैरामीटर में पास करते हैं, लेकिन जब से आप एक std::function पास नहीं करते हैं std::function यह T नहीं निकाल सकता है और इसके कारण, आपको एक मिलता है त्रुटि।


जबकि मैं समझता हूं कि आम तौर पर एसटीडी :: फंक्शन पैरामीटर का प्रकार घटाया नहीं जा सकता क्योंकि यह एक गैर-कटौती वाला संदर्भ है

यह एक गैर-कटौती संदर्भ नहीं है। बिल्कुल इसके विपरीत। क्योंकि std::funcition के पैरामीटर के लिए कटौती का प्रयास किया जाता है, लेकिन तर्क कोई std::function , कटौती विफल रहती है। फ़ंक्शन तर्क से टेम्पलेट तर्क की कटौती सभी फ़ंक्शन तर्क के लिए सहमत होना चाहिए। यदि यह एक के लिए विफल रहता है, तो यह पूरी तरह से विफल हो जाता है।

[temp.deduct.type]

2 कुछ मामलों में, कटौती एक प्रकार के P और A के सेट का उपयोग करके की जाती है, अन्य मामलों में, संबंधित प्रकार P और A का एक सेट होगा। प्रत्येक P / A जोड़ी के लिए स्वतंत्र रूप से प्रकार की कटौती की जाती है, और कटौती की जाती है। टेम्पलेट तर्क मान तब संयुक्त होते हैं। यदि किसी पी / ए जोड़ी के लिए टाइप कटौती नहीं की जा सकती है, या किसी भी जोड़ी के लिए कटौती कटौती मूल्यों के एक से अधिक संभावित सेट की ओर ले जाती है, या यदि अलग-अलग जोड़े अलग-अलग कटौती मूल्यों का उत्पादन करते हैं, या यदि कोई टेम्पलेट तर्क न तो घटाया जाता है और न ही स्पष्ट रूप से निर्दिष्ट, टेम्पलेट तर्क कटौती विफल हो जाती है।

दूसरे फ़ंक्शन पैरामीटर के प्रकार को गैर-कटौती किए गए संदर्भ में बनाना वास्तव में है कि कोई कैसे त्रुटि को दूर कर सकता है:

#include <functional>

template<typename T>
struct type_identity {
    using type = T;
};

template <typename> 
struct S { };

void g(S<int> ) {}

template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type) {}

int main() {
    f(0, g);
}

T पहले फ़ंक्शन तर्क से सफलतापूर्वक कटौती की जाती है, और कटौती करने के लिए कुछ भी नहीं बचा है। तो कटौती को एक सफलता माना जाता है।

Live







template-deduction