2012-04-03 9 views
41

शामिल कर रहे हैं जब मैं इस समारोह को परिभाषित,सी ++ 11 प्रकार अनुमान नहीं है जब std :: समारोह या लैम्ब्डा कार्यों

template<class A> 
set<A> test(const set<A>& input) { 
    return input; 
} 

मैं इसे कोड में कहीं test(mySet) का उपयोग कर स्पष्ट रूप से परिभाषित करने के लिए बिना कॉल कर सकते हैं टेम्पलेट प्रकार। हालांकि, जब मैं निम्नलिखित समारोह का उपयोग करें:

template<class A> 
set<A> filter(const set<A>& input,function<bool(A)> compare) { 
    set<A> ret; 
    for(auto it = input.begin(); it != input.end(); it++) { 
     if(compare(*it)) { 
      ret.insert(*it); 
     } 
    } 
    return ret; 
} 

जब मैं इस समारोह का उपयोग कर फोन filter(mySet,[](int i) { return i%2==0; }); मैं निम्नलिखित त्रुटि मिलती है:

error: no matching function for call to ‘filter(std::set&, main()::)’

हालांकि, इन संस्करणों के सभी काम करते हैं:

std::function<bool(int)> func = [](int i) { return i%2 ==0; }; 
set<int> myNewSet = filter(mySet,func); 

set<int> myNewSet = filter<int>(mySet,[](int i) { return i%2==0; }); 

set<int> myNewSet = filter(mySet,function<bool(int)>([](int i){return i%2==0;})); 

सी ++ 11 टेम्पलेट प्रकार का अनुमान लगाने में असमर्थ क्यों है जब मैं लैम्ब्डा फ़ंक्शन डायरेक्ट डालता हूं अभिव्यक्ति के अंदर y std::function सीधे बनाये बिना?

संपादित करें:

टिप्पणी में प्रति ल्यूक डेंटन की सलाह

, यहाँ समारोह मैंने पहले किया था कि स्पष्ट रूप से पारित होने के लिए टेम्पलेट्स की जरूरत नहीं है के लिए एक विकल्प है।

template<class A,class CompareFunction> 
set<A> filter(const set<A>& input,CompareFunction compare) { 
    set<A> ret; 
    for(auto it = input.begin(); it != input.end(); it++) { 
     if(compare(*it)) { 
      ret.insert(*it); 
     } 
    } 
    return ret; 
} 

इसे टेम्पलेट की आवश्यकता के बिना set<int> result = filter(myIntSet,[](int i) { i % 2 == 0; }); द्वारा बुलाया जा सकता है।

कंपाइलर नए अस्वीकरण कीवर्ड का उपयोग करके और नए फ़ंक्शन रिटर्न प्रकार सिंटैक्स का उपयोग करके कुछ हद तक रिटर्न प्रकार का अनुमान लगा सकता है।

template<class Value,class CompareType,class IndexType> 
auto filter(const set<Value>& input,CompareType compare,IndexType index) -> map<decltype(index(*(input.begin()))),Value> { 
    map<decltype(index(*(input.begin()))),Value> ret; 
    for(auto it = input.begin(); it != input.end(); it++) { 
     if(compare(*it)) { 
      ret[index(*it)] = *it; 
     } 
    } 
    return ret; 
} 

यह भी टेम्पलेट सीधे का उपयोग किए बिना कहा जा सकता है,

के रूप में: यहाँ एक उदाहरण है कि एक नक्शा करने के लिए एक सेट बदल देता है, एक छानने समारोह और एक समारोह है कि मूल्यों पर आधारित कुंजी उत्पन्न करता है उपयोग कर रहा है
map<string,int> s = filter(myIntSet,[](int i) { return i%2==0; },[](int i) { return toString(i); }); 
+5

आपके प्रश्न से संबंधित नहीं है, लेकिन आपको पता है कि आपका 'फ़िल्टर' अनिवार्य रूप से 'std :: copy_if' के गैर-सामान्य संस्करण के बराबर है, है ना? –

+0

आह, मुझे std :: copy_if के बारे में पता नहीं था, इसे इंगित करने के लिए धन्यवाद। हालांकि, यह 4 कार्यों के एक बड़े समूह का हिस्सा है, जो फ़िल्टरिंग करते समय सेट => मानचित्र को परिवर्तित करता है और मुझे इसे कॉपी करने के लिए एक तरीका नहीं दिखता है और सेट में मानों का उपयोग करके उपयोगकर्ता को कुंजी बनाने की अनुमति देता है। उपयोग में स्थिरता के लिए, मैं इसे इस तरह से करने का विकल्प चुन रहा हूं। – Datalore

उत्तर

50

मुद्दा लैम्बदास की प्रकृति पर है। वे मानक के अनुसार गुणों के एक निश्चित सेट के साथ कार्य ऑब्जेक्ट्स हैं, लेकिन वे फ़ंक्शन नहीं हैं। मानक निर्धारित करता है कि लैम्बडा को std::function<> में सही प्रकार के तर्कों के साथ परिवर्तित किया जा सकता है, और यदि उनके पास कोई राज्य, फ़ंक्शन पॉइंटर्स नहीं हैं।

लेकिन इसका मतलब यह नहीं है कि एक लैम्ब्डा std::function और न ही फ़ंक्शन पॉइंटर है। वे operator() लागू करने वाले अद्वितीय प्रकार हैं।

दूसरी तरफ कटौती टाइप करें, केवल रूपांतरणों को कम करेगा, बिना किसी रूपांतरण (कॉन्स/अस्थिर योग्यता के अलावा)। चूंकि लैम्ब्डा std::function नहीं है क्योंकि संकलक कॉल में टाइप को कम नहीं कर सकता: filter(mySet,[](int i) { return i%2==0; }); कोई std::function<> तत्कालता होने के लिए।

अन्य उदाहरणों के अनुसार, पहले में आप लैम्ब्डा को फ़ंक्शन प्रकार में परिवर्तित करते हैं, और फिर उसे पास करते हैं। कंपाइलर उस प्रकार को कम कर सकता है, जैसा कि तीसरे उदाहरण में std::function एक ही प्रकार का एक रैल्यू (अस्थायी) है।

यदि आप टेम्पलेट में तत्काल प्रकार int प्रदान करते हैं, तो दूसरा कामकाजी उदाहरण, कटौती खेल में नहीं आती है, संकलक प्रकार का उपयोग करेगा और फिर लैम्ब्डा को उचित प्रकार में परिवर्तित करेगा।

+11

ध्यान दें कि यह lambda नहीं है जो 'std :: function' में रूपांतरण करता है, यह' std :: function' है जो कॉल करने योग्य कुछ भी स्वीकार करता है। – Xeo

+0

टाइप कटौती पूर्ण होने के लिए आधार-प्रकार "रूपांतरण" भी करेगी। – Yakk

+3

इसे 'तुलना' तर्क के लिए कटौती को अक्षम करके काम करने के लिए किया जा सकता है।हम इस हस्ताक्षर के साथ ऐसा कर सकते हैं: 'टेम्पलेट फ़िल्टर सेट (स्थिरांक और इनपुट निर्धारित करते हैं, typename NOOP <समारोह > :: प्रकार की तुलना )' जहां '' Noop' के रूप में टेम्पलेट struct NOOP परिभाषित किया गया है { टाइपपीफ टी प्रकार; }; ' –

7

अपने मामले के बारे में भूल जाओ। क्योंकि यह विश्लेषण के लिए बहुत जटिल है।

template<typename T> 
struct X 
{ 
    X(T data) {} 
}; 

template<typename T> 
void f(X<T> x) {} 

अब f फोन के रूप में:

f(10); 

यहाँ आप को लगता है कि Tintऔर इसलिए, ऊपर कार्य करने के लिए निष्कर्ष निकाला की जाएगी परीक्षा हो सकती है

इस सरल उदाहरण लें कॉल काम करना चाहिए। खैर, यह मामला नहीं है। बात सरल रखने के लिए, यह अनुमान है कि वहाँ एक और निर्माता जो int के रूप में लेता है:

template<typename T> 
struct X 
{ 
    X(T data) {} 
    X(int data) {} //another constructor 
}; 

अब क्या T को निष्कर्ष निकाला जाना चाहिए, मैं जब लिखना f(10)? खैर, Tकोई प्रकार हो सकता है।

ध्यान दें कि ऐसे कई अन्य मामले हो सकते हैं। उदाहरण के लिए इस विशेषज्ञता ले लो,:

template<typename T> 
struct X<T*>   //specialized for pointers 
{ 
    X(int data) {}; 
}; 

अब क्या T कॉल f(10) के लिए करने के लिए निष्कर्ष निकाला जाना चाहिए? अब यह और भी कठिन लगता है।

इसलिए यह गैर-deducible संदर्भ है, जो बताता है कि आपका कोड std::function के लिए क्यों काम नहीं करता है जो एक समान मामला — बस सतह पर जटिल दिखता है। ध्यान दें कि lambdas वे मूल रूप से संकलक उत्पन्न वर्गों के उदाहरण हैं (यानी वे std::function से अलग प्रकार के functors रहे हैं) कर रहे हैं प्रकार std::function — की नहीं हैं।

संबंधित मुद्दे