2011-06-28 32 views
14

std::function का उपयोग करके, हम argument_type, second_argument_type आदि टाइपिंगफ्स का उपयोग करके तर्क का प्रकार प्राप्त कर सकते हैं, लेकिन मुझे लैम्ब्स के साथ एक ही चीज़ करने का कोई तरीका नहीं दिख रहा है। क्या यह संभव है?क्या हम लैम्ब्डा तर्क का प्रकार प्राप्त कर सकते हैं?

template<typename F> 
static void forward(F f) 
{ 
    // Create an object of the type of the first 
    // parameter to the function object F 
    typedef typename F::argument_type T; 
    T t; 

    //...do something with 't' here (deserialize in my case) 

    // Forward the object to the function 
    f(t); 
} 

यह इस और सब कुछ की तरह इस्तेमाल किया जा सकता है: (मैं VS2010 उपयोग कर रहा हूँ)

मैं अपने अक्रमांकन एक वस्तु पढ़ सकते हैं और यह एक सेटर कार्य करने के लिए पारित करने के लिए इस्तेमाल किया प्रणाली में निम्नलिखित की तरह कुछ चाहते कहो ठीक काम करता है:

std::function<void(int)> f = [](int i) -> void { setValue(i); }; 
forward(f); 

लेकिन यह सीधे lambdas साथ काम नहीं करेंगे:

forward([](int i) -> void { setValue(i); }); 
//error C2039: 'argument_type' : is not a 
//member of '`anonymous-namespace'::<lambda1>' 

क्या पैरामीटर प्रकारों को इस तरह से एक्सेस करने का कोई तरीका है जो लैम्बडास और std::function ऑब्जेक्ट्स दोनों के लिए काम करेगा? हो सकता है कि std::function पहले लैम्ब्डा का प्रकार प्राप्त करें, और उसके बाद argument_type?


नीचे जवाब है, एक ऐसा संस्करण है और std::function lambdas के साथ काम करता से इसे जारी रखते हुए है:

template<typename T, typename F> 
static void forward(F f) 
{ 
    T t; 

    //...do something with 't' here (deserialize in my case) 

    f(t); 
} 

forward<int>([](int i) -> void { setValue(i); }); 

int के बाद से यहां दोहराया है मैं इसे से छुटकारा पाने की उम्मीद कर रहा था - तो int के लिए बुरा नहीं लेकिन कुछ नामस्थानों में लंबे नाम वाले प्रकारों के लिए अधिक परेशान। C'est ला vie!

+2

संक्षिप्त उत्तर: नहीं। – ildjarn

+0

लंबा उत्तर: हाँ, नीचे देखें। –

उत्तर

16

यह सामान्य मामले में वांछनीय नहीं है। (ध्यान दें कि यह काफी आसान std::function<T(A)> निर्दिष्ट करने के लिए के लिए क्या argument_type जैसे है: यह सिर्फ A है यह प्रकार परिभाषा में उपलब्ध है!।)

यह अपने तर्क प्रकार निर्दिष्ट करने के लिए प्रत्येक और हर समारोह ऑब्जेक्ट प्रकार की आवश्यकता के लिए संभव हो जाएगा, और बदले में जनादेश है कि लैम्ब्डा अभिव्यक्ति से उत्पन्न बंद प्रकार ऐसा करते हैं। वास्तव में, प्री-सी ++ 0 एक्स फीचर्स जैसे अनुकूलनीय फ़ैक्टर केवल ऐसे प्रकार के लिए काम करेंगे।

हालांकि, हम उस से सी ++ 0x और अच्छे कारणों से आगे बढ़ रहे हैं। जिनमें से सबसे सरल बस अधिभारित होता है: एक टेम्पलेट operator() (ए.के.ए. एक पॉलिमॉर्फिक फ़ैक्टर) वाला एक मजेदार प्रकार बस सभी प्रकार के तर्क लेता है; तो argument_type क्या होना चाहिए? एक अन्य कारण यह है कि जेनेरिक कोड (आमतौर पर) उपयोग किए जाने वाले प्रकारों और वस्तुओं पर कम से कम बाधाओं को निर्दिष्ट करने का प्रयास करता है ताकि इसे आसानी से (पुनः) उपयोग किया जा सके।

दूसरे शब्दों में, सामान्य कोड है कि Functor f दिया, typename Functor::argumentint हो वास्तव में दिलचस्पी नहीं है। यह अधिक जानना दिलचस्प है कि f(0) एक स्वीकार्य अभिव्यक्ति है। इस सी ++ 0x के लिए decltype और std::declval (आसानी से std::result_of के अंदर दो पैकेजिंग) जैसे टूल प्रदान करते हैं।

जिस तरह से मैं इसे देखता हूं आपके पास दो विकल्प हैं: यह आवश्यक है कि आपके टेम्पलेट में पास किए गए सभी फ़ैक्टर argument_type निर्दिष्ट करने के लिए एक C++ 03-शैली सम्मेलन का उपयोग करें; नीचे तकनीक का उपयोग करें; या फिर से डिजाइन करें। मैं अंतिम विकल्प की अनुशंसा करता हूं लेकिन यह आपकी कॉल है क्योंकि मुझे नहीं पता कि आपका कोडबेस कैसा दिखता है या आपकी आवश्यकताएं क्या हैं।


एक monomorphic functor प्रकार (अर्थात् कोई अधिक भार) के लिए, यह operator() सदस्य निरीक्षण करने के लिए संभव है। यह लैम्ब्डा अभिव्यक्तियों के बंद प्रकारों के लिए काम करता है।

तो हम इन सहायकों

template<typename F, typename Ret, typename A, typename... Rest> 
A 
helper(Ret (F::*)(A, Rest...)); 

template<typename F, typename Ret, typename A, typename... Rest> 
A 
helper(Ret (F::*)(A, Rest...) const); 

// volatile or lvalue/rvalue *this not required for lambdas (phew) 

कि कम से कम एक तर्क लेने सदस्य कार्य करने के लिए एक सूचक को स्वीकार घोषणा करते हैं। और अब:

template<typename F> 
struct first_argument { 
    typedef decltype(helper(&F::operator())) type; 
}; 

[। एक विस्तृत विशेषता क्रमिक lvalue-rvalue/स्थिरांक/अस्थिर भार के क्वेरी और सभी भार के लिए पहला तर्क का पर्दाफाश करता है, तो यह एक ही है, या std::common_type इस्तेमाल कर सकते हैं]

+0

ग्रेट स्पष्टीकरण धन्यवाद। मैंने रीडिज़ाइन का चयन किया (टाइप 'टी' एक टेम्पलेट पैरामीटर भी है) लेकिन मुझे उम्मीद थी कि मैं इसे किसी भी तरह से छुटकारा पाने में सक्षम हूं क्योंकि यह अनावश्यक नकल की तरह लग रहा था। –

+0

मेरा वास्तविक कोड वास्तव में कब्जे वाले चर (आमतौर पर ऑब्जेक्ट जिस पर सेटर विधि को कॉल करने के लिए) होता है लेकिन स्पष्टीकरण के लिए धन्यवाद। –

+1

क्या आप उस तरह कुछ ऐसा करने में सक्षम नहीं होना चाहिए, लेकिन 'एफ' का विश्लेषण करने के बजाय '& F :: ऑपरेटर()' और पॉइंटर-टू-सदस्य-फ़ंक्शंस के साथ? वह लैम्ब्स के लिए काम करेगा जो कैप्चर स्वीकार करता है, मुझे लगता है। –

2

@ ल्यूक के इस सवाल का जवाब बहुत अच्छा है लेकिन मैं सिर्फ एक मामले में जहां मैं भी समारोह संकेत के साथ सौदा करने के लिए आवश्यक भर में आया था:

:

template<typename Ret, typename Arg, typename... Rest> 
Arg first_argument_helper(Ret(*) (Arg, Rest...)); 

template<typename Ret, typename F, typename Arg, typename... Rest> 
Arg first_argument_helper(Ret(F::*) (Arg, Rest...)); 

template<typename Ret, typename F, typename Arg, typename... Rest> 
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const); 

template <typename F> 
decltype(first_argument_helper(&F::operator())) first_argument_helper(F); 

template <typename T> 
using first_argument = decltype(first_argument_helper(std::declval<T>())); 

यह दोनों functors और समारोह संकेत पर इस्तेमाल किया जा सकता

void function(float); 

struct functor { 
    void operator() (int); 
}; 

int main() { 
    std::cout << std::is_same<first_argument<functor>, int>::value 
       << ", " 
       << std::is_same<first_argument<decltype(&function)>, int>::value 
       << std::endl; 
    return 0; 

} 
+0

मूल रूप से मैंने इसके साथ एक समस्या की सूचना दी, लेकिन अब मुझे एहसास हुआ कि मैंने गलती की है। [यहां यह ऑनलाइन है] (http://coliru.stacked-crooked.com/a/7660f42b6e2a7476)। – doug65536

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