2012-02-11 11 views
17

test नामक एक फ़ंक्शन std :: function <> इसके पैरामीटर के रूप में लेता है।सी ++ 11 variadic std :: फ़ंक्शन पैरामीटर

template<typename R, typename ...A> 
void test(std::function<R(A...)> f) 
{ 
    // ... 
} 

लेकिन, अगर मैं निम्न कार्य करें:

void foo(int n) { /* ... */ } 

// ... 

test(foo); 

संकलक (जीसीसी 4.6.1) का कहना है no matching function for call to test(void (&)(int))

अंतिम पंक्ति test(foo) को संकलित और ठीक से काम करने के लिए, मैं test() फ़ंक्शन को कैसे संशोधित कर सकता हूं? test() फ़ंक्शन में, मुझे f की आवश्यकता है std :: function <> के प्रकार के साथ।

मेरा मतलब है, क्या कंपाइलर फ़ंक्शन के हस्ताक्षर (foo उदाहरण में) निर्धारित करने के लिए कोई टेम्पलेट चाल है, और इसे स्वचालित रूप से std::function<void(int)> में परिवर्तित कर देता है?

संपादित

मैं lambdas (दोनों ने कहा और स्टेटलेस) और साथ ही के लिए यह काम करना चाहते हैं।

उत्तर

11

ऐसा लगता है कि आप

template<typename R, typename ...A> 
void test(R f(A...)) 
{ 
    test(std::function<R(A...)>(f)); 
} 

यह सरल कार्यान्वयन अधिक भार नहीं तो सभी कार्यों आप पारित करने की कोशिश करेंगे सबसे स्वीकार करेंगे उपयोग करना चाहते हैं। विदेशी कार्यों को खारिज कर दिया जाएगा (जैसे void(int...))। अधिक काम आपको अधिक सामान्यता देगा।

+0

क्या lambdas के बारे में (दोनों ने कहा और स्टेटलेस)? –

+4

@ डैनियल आप भाग्य से बाहर हैं। या 'टेस्ट' एक टेम्पलेट बनाएं जो कुछ भी स्वीकार करता है ('टी')। 'std :: function' असंगत फ़ंक्शन ऑब्जेक्ट्स को वैसे भी अस्वीकार नहीं करेगा, इसलिए फ़ंक्शन टेम्पलेट पैरामीटर के प्रकार को सीमित करने का उद्देश्य यहां मेरे लिए बहुत उपयोगी नहीं लगता है। –

+1

मैंने '(टी)' के साथ प्रयास किया, लेकिन, इसे 'std :: function ' पर कैसे बनाया जा सकता है? ऐसा लगता है कि मैं 'std :: result_of <>' का उपयोग करके 'आर' प्राप्त कर सकता हूं, लेकिन 'ए ...'? –

4

आमतौर पर std::function को मूल्य से तब तक बीमार सलाह दी जाती है जब तक कि आप 'बाइनरी डिलीमिशन' (उदा। गतिशील लाइब्रेरी, 'ओपेक' एपीआई) पर न हों, क्योंकि आपने देखा है कि वे ओवरलोडिंग के साथ कहर बरकरार रखते हैं। जब कोई फ़ंक्शन वास्तव में std::function मान द्वारा लेता है तो अधिभार समस्याओं को टालने के लिए ऑब्जेक्ट का निर्माण करने के लिए अक्सर कॉलर का बोझ होता है (यदि फ़ंक्शन ओवरलोड हो जाता है)।

चूंकि आपने एक टेम्पलेट लिखा है, इसलिए यह संभावना है कि आप टाइप-एरर के लाभों के लिए std::function (पैरामीटर प्रकार के रूप में) का उपयोग नहीं कर रहे हैं। यदि आप जो करना चाहते हैं वह मनमाने ढंग से मज़दूरों का निरीक्षण कर रहा है तो आपको इसके लिए कुछ विशेषताओं की आवश्यकता है। जैसे Boost.FunctionTypes में result_type और parameter_types जैसे लक्षण हैं। एक न्यूनतम, कार्यात्मक उदाहरण:

#include <functional> 

#include <boost/function_types/result_type.hpp> 
#include <boost/function_types/parameter_types.hpp> 
#include <boost/function_types/function_type.hpp> 

template<typename Functor> 
void test(Functor functor) // accept arbitrary functor! 
{ 
    namespace ft = boost::function_types; 

    typedef typename ft::result_type<Functor>::type result_type; 
    typedef ft::parameter_types<Functor> parameter_types; 
    typedef typename boost::mpl::push_front< 
     parameter_types 
     , result_type 
    >::type sequence_type; 
    // sequence_type is now a Boost.MPL sequence in the style of 
    // mpl::vector<int, double, long> if the signature of the 
    // analyzed functor were int(double, long) 

    // We now build a function type out of the MPL sequence 
    typedef typename ft::function_type<sequence_type>::type function_type; 

    std::function<function_type> function = std::move(functor); 
} 

एक अंतिम नोट के रूप में, मैं आत्मनिरीक्षण functors सामान्य स्थिति है कि बस बहुरूपी functors लिए काम नहीं करते के रूप में में (अर्थात उनके परिणाम के प्रकार और तर्क प्रकारों के लिए उकसा रही है) की सलाह नहीं देते। कई ओवरलोडेड operator() पर विचार करें: फिर कोई 'कैनोलिक' परिणाम प्रकार या तर्क प्रकार नहीं है। सी ++ 11 के साथ किसी भी प्रकार के मज़ेदार को 'उत्सुकता से' स्वीकार करना बेहतर होता है, या जरूरतों के आधार पर एसएफआईएनएई या static_assert जैसी तकनीकों का उपयोग करके और बाद में (जब पैरामीटर उपलब्ध होते हैं) std::result_of का उपयोग करने के लिए परिणाम प्रकार का निरीक्षण करने के लिए बेहतर होता है तर्कों का एक निर्धारित सेट। एक मामला जहां आगे बढ़ना वांछनीय है, जब लक्ष्य मज़ेदारों को उदा। std::function<Sig> का एक कंटेनर।

पिछले अनुच्छेद से मेरा क्या मतलब है इसका स्वाद प्राप्त करने के लिए यह पॉलिमॉर्फिक फ़ैक्टरों के साथ उपरोक्त स्निपेट का परीक्षण करने के लिए पर्याप्त है।

5

std::function कॉल करने योग्य इंटरफ़ेस लागू करता है, यानी यह एक फ़ंक्शन जैसा दिखता है, लेकिन इसका मतलब यह नहीं है कि आपको कॉल करने योग्य ऑब्जेक्ट्स std::function एस होना चाहिए।

template< typename F > // accept any type 
void test(F const &f) { 
    typedef std::result_of< F(args) >::type R; // inspect with traits queries 
} 

बतख टाइपिंग टेम्पलेट metaprogramming में सर्वोत्तम नीति है। टेम्पलेट तर्क स्वीकार करते समय, अनपेक्षित रहें और क्लाइंट को इंटरफ़ेस को लागू करने दें।

आप वास्तव में लिए उदाहरण के लिए एक std::function की जरूरत है चर या ऐसा पागल कुछ फिर से लक्षित करते हैं, और आप जानते हैं इनपुट एक कच्चे समारोह सूचक है, तो आप एक कच्चे समारोह सूचक प्रकार विघटित और एक में यह कर सकते हैं reconsitute std::function

template< typename R, typename ... A > 
void test(R (*f)(A ...)) { 
    std::function< R(A ...) > internal(f); 
} 

अब उपयोगकर्ता एक std::function पारित नहीं हो सकता, क्योंकि वह समारोह के भीतर समझाया गया है। आप अपने मौजूदा कोड को एक और अधिभार के रूप में रख सकते हैं और बस उस पर प्रतिनिधि हो सकते हैं, लेकिन इंटरफ़ेस को सरल रखने के लिए सावधान रहें।

राज्यव्यापी भेड़ के बच्चे के रूप में, मुझे नहीं पता कि उस मामले को कैसे संभालना है। वे फंक्शन पॉइंटर्स को विघटित नहीं करते हैं और जहां तक ​​मुझे पता है कि तर्क प्रकारों को पूछताछ या कटौती नहीं की जा सकती है। बेहतर या बदतर के लिए std::function को तुरंत चालू करने के लिए यह जानकारी आवश्यक है।

+1

मेरा मानना ​​है कि सही शब्द गतिशील बाध्यकारी होगा - 'बतख टाइपिंग' शब्द का उपयोग – serup

+0

@serup Google => "देर बाध्यकारी, या गतिशील बाध्यकारी, एक कंप्यूटर प्रोग्रामिंग तंत्र है जिसमें ऑब्जेक्ट पर विधि कहा जा रहा है या तर्क के साथ बुलाया जाने वाला फ़ंक्शन रनटाइम पर नाम से देखा जाता है। " टेम्पलेट्स पर लागू नहीं है। – Potatoswatter

+0

फिर बतख टाइपिंग शब्द का उपयोग क्यों करें? – serup

2

यह एक पुराना है, और मुझे एक ही विषय पर बहुत कुछ नहीं मिल रहा है, इसलिए मैंने सोचा कि मैं आगे बढ़ूंगा और एक नोट डालूंगा।

जीसीसी 4.8.2, निम्नलिखित कार्यों पर संकलित:

template<typename R, typename... A> 
R test(const std::function<R(A...)>& func) 
{ 
    // ... 
} 
हालांकि

, तुम बस, आदि हालांकि साथ अपने संकेत दिए गए, lambdas में गुजर, निम्नलिखित 2 उदाहरण दोनों काम से यह कॉल नहीं कर सकते यह:

test(std::function<void(int, float, std::string)>(
     [](int i, float f, std::string s) 
     { 
      std::cout << i << " " << f << " " << s << std::endl; 
     })); 
इसके अलावा

:

void test2(int i, float f, std::string s) 
{ 
    std::cout << i << " " << f << " " << s << std::endl; 
} 

// In a function somewhere: 
test(std::function<void(int, float, std::string)>(&test2)); 

इनमें से नकारात्मक पक्ष यह बहुत स्पष्ट रूप से बाहर खड़े होना चाहिए: यो आपको उनके लिए std :: फ़ंक्शन स्पष्ट रूप से घोषित करना होगा, जो थोड़ा बदसूरत लग सकता है।

उस ने कहा, हालांकि, मैंने उस ट्यूपल के साथ एक साथ फेंक दिया जो आने वाले फ़ंक्शन को कॉल करने के लिए विस्तारित हो जाता है, और यह काम करता है, केवल एक स्पष्ट रूप से यह कहने की आवश्यकता है कि आप परीक्षण फ़ंक्शन को कॉल कर रहे हैं।

टपल बात सहित उदाहरण कोड, आप इसके साथ खेलने के लिए चाहते हैं: http://ideone.com/33mqZA

+1

बस किक्स के लिए, मैं index_sequence का उपयोग कर एक विधि के साथ आया (सी ++ 14 में जोड़ा जा रहा है, लेकिन सी ++ 11 में स्वयं को लागू करना आसान है) और फ़ंक्शन_ट्रेट्स स्टाइल स्ट्रक्चर कुछ के साथ आने के लिए वह किसी भी लैम्ब्डा, मज़ेदार, या समारोह ले जाएगा, और इसका इस्तेमाल करेंगे। [http://ideone.com/LNpj74 ](http://ideone.com/LNpj74) इसका एक उदाहरण दिखाता है। नोट, हालांकि, 2+ ऑपरेटर() ओवरलोड किए गए म्यूटर्स के लिए, इसे अभी भी उपयोग करने के लिए निर्दिष्ट प्रकारों को निर्दिष्ट करने के लिए एक अतिरिक्त इंटरफ़ेस की आवश्यकता होती है। इसे पॉलिमॉर्फिक फ़ैक्टर के साथ आज़माएं नहीं, लेकिन मुझे उम्मीद है कि इससे समस्याएं भी पैदा होंगी ... – user3694249

+0

जैसा कि 'std :: function' का उपयोग करके, टेम्पलेट्स उपलब्ध होने पर, Potatoswatter ऊपर उल्लिखित है, गतिशील आवंटन ओवरहेड और बॉयलरप्लेट का ढेर है कोई लाभ नहीं के लिए। बस एक सामान्य फ़ंक्शन टेम्पलेट बनाने के लिए बेहतर है जो पूरे स्थान पर 'std :: function' में खींचने से लैम्बडा स्वीकार कर सकता है। –