2014-06-27 7 views
6

मेरे पास उपयोगकर्ता परिभाषित प्रकार (छात्र) का वेक्टर है। मेरे पास 2 फ़ंक्शन हैं जो लगभग एक ही फ़ंक्शन कॉल को छोड़कर लगभग समान हैं।किसी अन्य फ़ंक्शन पर एसटीएल एल्गोरिदम पास करना

यहाँ 2 कार्यों है:

Student lowest_grade(const std::vector<Student> &all_students){ 
    return *std::min_element(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
} 

Student highest_grade(const std::vector<Student> &all_students){ 
    return *std::max_element(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
} 
इन कार्यों के

दोनों अपने प्रयोग के लिए सही ढंग से काम कर रहे हैं लेकिन ऐसा लगता है जैसे यह आसानी से बेहतर निर्माण किया जा सकता है। मैं एक समारोह जो मैं या तो min_element या max_element पास कर सकता है, जैसे कुछ बनाना चाहते हैं:

template <typename func> 
Student dispatch(const std::vector<Student> &all_students, func){ 
    return *func(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
} 

लेकिन मैं इसे पाने के लिए ठीक से काम करने का प्रबंधन नहीं कर सकते हैं। मुझे यकीन नहीं है कि यह करने के बारे में कैसे जाना है।

संपादित करें - यह है कि कैसे मैं प्रेषण समारोह + त्रुटि संदेश बोल रहा हूँ:

std::cout<<"lowest: "<< dispatch(all_students, std::max_element); 

त्रुटि संदेश है:

g++ m.cpp -std=c++11 -Wall -o main 
m.cpp: In function ‘int main()’: 
m.cpp:86:63: error: missing template arguments before ‘(’ token 
    std::cout<<"lowest: "<< dispatch(all_students, std::function(std::max_element)); 
                  ^
[email protected]:~/Desktop/Prog/daily/167m$ make 
g++ m.cpp -std=c++11 -Wall -o main 
m.cpp: In function ‘int main()’: 
m.cpp:86:81: error: no matching function for call to ‘dispatch(std::vector<Student>&, <unresolved overloaded function type>)’ 
    std::cout<<"lowest: "<< dispatch<std::function>(all_students, std::max_element); 
                       ^
m.cpp:86:81: note: candidate is: 
m.cpp:71:9: note: template<class func> Student dispatch(const std::vector<Student>&, func) 
Student dispatch(const std::vector<Student> &all_students, func){ 
     ^
m.cpp:71:9: note: template argument deduction/substitution failed: 
+0

क्या आप कृपया यह बता सकते हैं कि यह कैसे काम नहीं कर रहा है? विशेष रूप से कृपया दिखाएं कि आप अपने 'प्रेषण' फ़ंक्शन का उपयोग कैसे करते हैं। –

+0

यदि आप एक ही समय में न्यूनतम और अधिकतम दोनों की गणना कर रहे हैं, तो [std :: minmax_element] (http://en.cppreference.com/w/cpp/algorithm/minmax_element) खाते में लें। –

उत्तर

1

आपका समारोह जिस तरह से आप चाहते हैं के रूप में निम्नानुसार लिखा जा सकता है:

template<typename Func> 
Student dispatch(const std::vector<Student> &all_students, Func func) 
{ 
    assert(!all_students.empty()); 
    return *func(std::begin(all_students), std::end(all_students), 
       [](const Student &a, const Student &b){ 
        return a.get_average() < b.get_average();}); 
} 

और के रूप में लागू किया

dispatch(students, 
     std::min_element<decltype(students)::const_iterator, 
          bool(*)(const Student&, const Student&)>); 
dispatch(students, 
     std::max_element<decltype(students)::const_iterator, 
          bool(*)(const Student&, const Student&)>); 

यदि आप Student के लिए लागू करते हैं तो आप वर्बोसिटी पर थोड़ा सा कटौती कर सकते हैं। यह आपको तुलनित्र के लिए टेम्पलेट तर्क को छोड़ने की अनुमति देगा।

template<typename Func> 
Student dispatch(const std::vector<Student> &all_students, Func func) 
{ 
    assert(!all_students.empty()); 
    return *func(std::begin(all_students), std::end(all_students)); 
} 

dispatch(students, 
     std::min_element<decltype(students)::const_iterator>); 
dispatch(students, 
     std::max_element<decltype(students)::const_iterator>); 

फिर भी एक और तरीका यह है, हमेशा प्रेषण भीतर min_element फोन, लेकिन अलग अलग व्यवहार के साथ तुलनाकारक में पारित करने के लिए है।

template<typename Comparator> 
Student dispatch(const std::vector<Student> &all_students, Comparator comp) 
{ 
    assert(!all_students.empty()); 
    return *std::min_element(std::begin(all_students), std::end(all_students), 
          comp); 
} 

dispatch(students, std::less<Student>()); 
dispatch(students, std::greater<Student>()); // requires operator> for Student 

अंत में, यदि आप हमेशा दोनों निम्नतम और उच्चतम ग्रेड लाने के लिए जा रहे हैं, मानक पुस्तकालय std::minmax_element है कि दोनों एक कॉल में लायेगा प्रदान करता है।

auto minmax = std::minmax_element(std::begin(students), std::end(students)); 

Live demo सभी अलग-अलग विकल्पों में से।

3

यह यह करना होगा:

template <typename func> 
Student dispatch(const std::vector<Student> &all_students, const func& fn){ 
    return *fn(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
} 

टेम्पलेट पैरामीटर सिर्फ कुछ प्रकार का है।

मैं इस विधि को खाली वेक्टर के साथ कभी भी कॉल करने के लिए सावधान रहने का सुझाव नहीं दूंगा, क्योंकि यह खाली इटरेटर को डिफ्रेंस करते समय अपवाद उठाएगा। बेहतर होगा:

template <typename func> 
Student dispatch(const std::vector<Student> &all_students, const func& fn){ 
    auto it = fn(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
    if (it != all_students.end()) { 
    return *it; 
    } 
    // Some exception handling, because returning an instance of student is not possible. 
} 

एक और सुझाव डेटा का उपयोग करने से पहले छात्रों को सॉर्ट करना है। फिर आप मध्यस्थ जैसे अन्य सांख्यिकीय डेटा भी प्राप्त कर पाएंगे।

std::sort(all_students.begin(), all_students.end() [](const Student &a, const Student &b){return a.get_average() < b.get_average();}); 

निम्नतम छात्र पहला तत्व है और अंतिम सबसे अधिक है। यह आपको अपवाद उठाने से भी रोक देगा।

आपकी कॉल के साथ एक और समस्या है। एसटीएल

dispatch(all_students, std::max_element<std::vector<Student>::const_iterator, std::function<bool(const Student &, const Student &)>>); 

कोई कटौती जादू करता है और जो max_element समारोह अपने अभाव से ही तय नहीं कर सकता: आप कॉल करने के लिए प्रेषण की तरह की जरूरत है। तो आपको इसे निर्दिष्ट करना होगा।

+0

मुझे स्पष्ट होना चाहिए था, मुझे एहसास हुआ कि इस तरह का सबसे अच्छा विकल्प है, हालांकि यह सी 11 सीखने पर काम करने के लिए सिर्फ एक छोटा डेमो प्रोग्राम है। –

2

std::max_element एक टेम्पलेट फ़ंक्शन है और संकलक इस तरह से आवश्यक टेम्पलेट प्रकार को कम नहीं कर सकता है।

आप जो प्रोटोटाइप आप चाहते हैं के लिए मजबूर करने के लिए निम्न का उपयोग कर सकते हैं:

// Your lambda as functor 
struct CompAverage 
{ 
    bool operator() (const Student & a, const Student & b) const 
    { 
     return a.get_average() < b.get_average(); 
    } 
}; 

using Student_IT = std::vector<Student>::const_iterator; 

Student dispatch(const std::vector<Student> &all_students, 
       Student_IT (*f)(Student_IT, Student_IT, CompAverage)) 
{ 
    return *f(std::begin(all_students), std::end(all_students), CompAverage{}); 
} 

int main() 
{ 
    std::vector<Student> v(42); 

    dispatch(v, &std::min_element); 
    dispatch(v, &std::max_element); 
    return 0; 
} 

Live example

2

ऐसा करने का मेरा पसंदीदा तरीका एल्गोरिदम को लैम्ब्डा में लपेटना है और फिर लैम्ब्डा को टेम्पलेट फ़ंक्शन में पास करना है। जब आप इसे मैक्रो में लपेटते हैं तो इसमें अच्छा वाक्यविन्यास होता है:

#define LIFT(...)             \ 
    ([](auto&&... args) -> decltype(auto) {      \ 
     return __VA_ARGS__(std::forward<decltype(args)>(args)...); \ 
    }) 

template <typename Func> 
Student dispatch(const std::vector<Student> &all_students, Func func){ 
    return *func(std::begin(all_students), std::end(all_students), 
     [](const Student &a, const Student &b){ 
    return a.get_average() < b.get_average();}); 
} 

// ... 

std::cout<<"lowest: "<< dispatch(all_students, LIFT(std::max_element)); 
+0

हालांकि मैं परिभाषित करने का प्रशंसक नहीं हूं, यह कुछ अच्छा जादू है :) –

+0

यह बेहद परिचित दिखता है। [उपयुक्त मशीनरी] (https://github.com/sjolsen/sjo/blob/master/lift.hh) के साथ, आप लैम्बडा के बदले 'ऑर्डर_बी (एमएफएलआईएफटी (get_average)) का भी उपयोग कर सकते हैं। –

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