2010-07-08 23 views
31

मैं इसएक समारोह है कि

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, T (f)(T,U)) 
{ 
    map<T,U> new; 
    for(auto it = old.begin(); it != old.end(); ++it) 
    { 
     new[it->first] = f(it->first,it->second); 
    } 
    return new; 
} 

और विचार की तरह एक विधि है कि आप इसे इस

BOOST_AUTO_TEST_CASE(MapMapValues_basic) 
{ 
    map<int,int> test; 
    test[1] = 1; 
    map<int,int> transformedMap = VlcFunctional::mapMapValues(test, 
     [&](int key, int value) -> int 
     { 
      return key + 1; 
     } 
    ); 
} 

की तरह फोन करता हूँ हालांकि मैं त्रुटि मिलती है तर्क के रूप में एक लैम्ब्डा अभिव्यक्ति स्वीकार करता लिखें : फ़ंक्शन टेम्पलेट का कोई उदाहरण "VlcFunctional :: mapMapValues" तर्क सूची तर्क प्रकारों से मेल खाता है: (std :: map, std :: allocator >>, __lambda1)

कोई विचार क्या मैं गलत कर रहा हूं? विजुअल स्टूडियो 2008 और इंटेल C++ कम्पाइलर 11.1

+0

के रूप में एक समारोह के पारित करने के लिए के कुछ उदाहरण है 'new' एक कीवर्ड आप एक चर' new' – Motti

+1

haha ​​कहा जाता है नहीं कर सकते। हां अच्छी तरह से देखा गया है, क्योंकि कोड सही टेम्पलेट तर्क नहीं ढूंढ रहा था, यह वास्तव में कभी संकलित नहीं हुआ था इसलिए संकलक ने मुझे यह इंगित करने के लिए कभी परेशान नहीं किया :) –

+0

मुझे यकीन नहीं है कि लैम्ब्डा फ़ंक्शन के लिए "-> int" की आवश्यकता है – serup

उत्तर

34

आपका फ़ंक्शन एक फ़ंक्शन पॉइंटर की अपेक्षा कर रहा है, न कि लैम्ब्डा।

सी ++ में, सामान्यतः, 3 प्रकार के "कॉल करने योग्य ऑब्जेक्ट्स" होते हैं।

  1. फ़ंक्शन पॉइंटर्स।
  2. फ़ंक्शन ऑब्जेक्ट्स।
  3. लैम्ब्डा फ़ंक्शन।

आप अपने समारोह इंटरफ़ेस में इन सभी का उपयोग करने के लिए सक्षम होना चाहते हैं, तो आप std::function इस्तेमाल कर सकते हैं:

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T, U)> f) 
{ 
    ... 
} 

इस समारोह की अनुमति देगा के तीन प्रकार के किसी भी उपयोग के नाम से जाना ऊपर कॉल करने योग्य वस्तुओं। हालांकि, इस सुविधा के लिए कीमत फ़ंक्शन पर इनोकेशन पर ओवरहेड की एक छोटी राशि है (आमतौर पर एक शून्य सूचक जांच, फिर फ़ंक्शन पॉइंटर के माध्यम से कॉल)। इसका मतलब है कि फ़ंक्शन लगभग निश्चित रूप से रेखांकित नहीं है (शायद उन्नत WPO/LTO के साथ)।

वैकल्पिक रूप से, आप दूसरे पैरामीटर के लिए मनमाना प्रकार लेने के लिए एक अतिरिक्त टेम्पलेट पैरामीटर जोड़ सकते हैं। यह अधिक कुशल होगा, लेकिन आप इस्तेमाल किए गए फ़ंक्शन पर टाइप-सुरक्षा खो देते हैं, और इससे अधिक कोड ब्लोट हो सकता है। खाली कब्जा सूची के साथ

template<typename T, typename U, typename F> 
map<T,U> mapMapValues(map<T,U> old, F f) 
+0

मैं std :: ट्रांसफॉर्म स्रोत को समझते समय दूसरे दृष्टिकोण पर ठोकर खाई, हालांकि मुझे अभी भी त्रुटि के कारण काम करने का पहला दृष्टिकोण नहीं मिल सकता है: नेमस्पेस "std" में कोई सदस्य "फ़ंक्शन" नहीं है। क्या मुझे कोई आवश्यकता है? –

+0

दूसरे दृष्टिकोण से संबंधित: एक बूस्ट से रिटर्न प्रकारों और पैरामीटर सूची निकालने के लिए 'बूस्ट' से उपयोगिताओं हैं, मुझे आश्चर्य है कि वे लैम्ब्डा या फ़ंक्शन ऑब्जेक्ट के साथ काम करेंगे और कोड के भीतर स्थिर आवेषण के साथ इसका उपयोग किया जा सकता है। –

+0

@matthieu, आप कौन सी उपयोगिताएं भी रेफर कर रहे हैं। मुझे विश्वास था कि बूस्ट :: फ़ंक्शन मुख्य रूप से उसी प्रभाव को प्राप्त कर सकता है जैसे @peter std :: function के साथ सुझाया गया है, हालांकि घोषणा में फ़ंक्शन पॉइंटर का उपयोग करने के समान समस्याएं थीं। –

12

आपका पैरामीटर प्रकार घोषणा T (f)(T,U) प्रकार के 'नि: शुल्क समारोह एक T और एक U ले रहे हैं और एक T लौटने' है। आप इसे एक लैम्ब्डा, फ़ंक्शन ऑब्जेक्ट या उस हस्ताक्षर के साथ वास्तविक फ़ंक्शन को छोड़कर कुछ भी नहीं पारित कर सकते हैं।

आप इस तरह std::function<T(T,U)> को पैरामीटर के प्रकार बदल कर इस का समाधान कर सकता:

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T,U)>) 
{ 
} 

वैकल्पिक रूप से, अगर आप इस तरह एक टेम्पलेट तर्क के रूप में समारोह प्रकार की घोषणा कर सकता है:

template<typename T, typename U, typename Fn> 
map<T,U> mapMapValues(map<T,U> old, Fn fn) 
{ 
    fn(...); 
} 
+0

धन्यवाद जो, मैंने पीटर के जवाब को केवल इसलिए चिह्नित किया क्योंकि वह आपके से एक मिनट तेज था। धन्यवाद था। –

5

लैम्ब्डा अभिव्यक्ति, संकेत कार्य करने के लिए क्षय चाहिए n3052 के अनुसार। हालांकि ऐसा लगता है कि यह सुविधा वीसी ++ में लागू नहीं हुई है और केवल आंशिक रूप से g ++ में है, मेरे SO question देखें।

+0

और इंटेल सी ++ 11.1 –

10

मैं इस सरल लेकिन आत्म-व्याख्यात्मक उदाहरण का योगदान देना चाहता हूं। यह दिखाता है कि "कॉल करने योग्य चीजें" (फ़ंक्शंस, फ़ंक्शन ऑब्जेक्ट्स, और लैम्बडास) को फ़ंक्शन या किसी ऑब्जेक्ट में कैसे पास किया जाए।

// g++ -std=c++11 thisFile.cpp 

#include <iostream> 
#include <thread> 

using namespace std; 

// ----------------------------------------------------------------- 
class Box { 
public: 
    function<void(string)> theFunction; 
    bool funValid; 

    Box() : funValid (false) { } 

    void setFun (function<void(string)> f) { 
    theFunction = f; 
    funValid = true; 
    } 

    void callIt() { 
    if (! funValid) return; 
    theFunction (" hello from Box "); 
    } 
}; // class 

// ----------------------------------------------------------------- 
class FunClass { 
public: 
    string msg; 
    FunClass (string m) : msg (m) { } 
    void operator() (string s) { 
    cout << msg << s << endl; 
    } 
}; 

// ----------------------------------------------------------------- 
void f (string s) { 
    cout << s << endl; 
} //() 

// ----------------------------------------------------------------- 
void call_it (void (*pf) (string)) { 
    pf("call_it: hello"); 
} //() 

// ----------------------------------------------------------------- 
void call_it1 (function<void(string)> pf) { 
    pf("call_it1: hello"); 
} //() 

// ----------------------------------------------------------------- 
int main() { 

    int a = 1234; 

    FunClass fc (" christmas "); 

    f("hello"); 

    call_it (f); 

    call_it1 (f); 

    // conversion ERROR: call_it ([&] (string s) -> void { cout << s << a << endl; }); 

    call_it1 ([&] (string s) -> void { cout << s << a << endl; }); 

    Box ca; 

    ca.callIt(); 

    ca.setFun (f); 

    ca.callIt(); 

    ca.setFun ([&] (string s) -> void { cout << s << a << endl; }); 

    ca.callIt(); 

    ca.setFun (fc); 

    ca.callIt(); 

} //() 
+1

में बिल्कुल नहीं, महान उदाहरण, धन्यवाद! :) –

+0

गैर-टेम्पलेट कंक्रीट प्रकार बिल्कुल वही थे जो मुझे देखने की ज़रूरत थी –

0

यहाँ कैसे पैरामीटर

class YourClass 
{ 
void YourClass::callback(void(*fptr)(int p1, int p2)) 
{ 
    if(fptr != NULL) 
     fptr(p1, p2); 
} 
}; 

void dummyfunction(int p1, int p2) 
{ 
    cout << "inside dummyfunction " << endl; 
} 

YourClass yc; 

// using a dummyfunction as callback 
yc.callback(&dummyfunction); 

// using a lambda as callback 
yc.callback([&](int p1, int p2) { cout << "inside lambda callback function" << endl; }); 

// using a static member function 
yc.callback(&aClass::memberfunction); 
संबंधित मुद्दे