क्या पैरामीटर प्रकार का पता लगाना और लंबोदर के प्रकार को वापस करना संभव है?


135

एक मेमने को देखते हुए, क्या यह पता लगाना संभव है कि यह पैरामीटर प्रकार और रिटर्न प्रकार है? यदि हाँ, तो कैसे?

मूल रूप से, मैं चाहता हूं कि lambda_traitsनिम्नलिखित तरीकों से उपयोग किया जा सके:

auto lambda = [](int i) { return long(i*10); };

lambda_traits<decltype(lambda)>::param_type  i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long

इसके पीछे प्रेरणा यह है कि मैं lambda_traitsएक फ़ंक्शन टेम्पलेट का उपयोग करना चाहता हूं जो एक लंबो को तर्क के रूप में स्वीकार करता है, और मुझे यह जानना होगा कि यह पैरामीटर प्रकार और फ़ंक्शन के अंदर वापसी प्रकार है:

template<typename TLambda>
void f(TLambda lambda)
{
   typedef typename lambda_traits<TLambda>::param_type  P;
   typedef typename lambda_traits<TLambda>::return_type R;

   std::function<R(P)> fun = lambda; //I want to do this!
   //...
}

कुछ समय के लिए, हम मान सकते हैं कि लैम्ब्डा बिल्कुल एक तर्क लेता है।

प्रारंभ में, मैंने इसके साथ काम करने की कोशिश की std::function:

template<typename T>
A<T> f(std::function<bool(T)> fun)
{
   return A<T>(fun);
}

f([](int){return true;}); //error

लेकिन यह स्पष्ट रूप से त्रुटि देगा। इसलिए मैंने इसे TLambdaफ़ंक्शन टेम्पलेट के संस्करण में बदल दिया और std::functionफ़ंक्शन के अंदर ऑब्जेक्ट का निर्माण करना चाहता हूं (जैसा कि ऊपर दिखाया गया है)।


यदि आप पैरामीटर प्रकार जानते हैं तो इसका उपयोग रिटर्न प्रकार का पता लगाने के लिए किया जा सकता है। मैं नहीं जानता कि कैसे पैरामीटर प्रकार का पता लगाना है।
मकारसे

क्या यह माना जाता है कि फ़ंक्शन एकल तर्क लेता है?
आइमिलिलिंड

1
"पैरामीटर प्रकार" लेकिन एक मनमाना लैम्ब्डा फ़ंक्शन में पैरामीटर प्रकार नहीं होता है। यह किसी भी संख्या में पैरामीटर ले सकता है। इसलिए किसी भी लक्षण वर्ग को स्थिति सूचकांकों द्वारा क्वेरी मापदंडों के लिए डिज़ाइन किया जाना चाहिए।
निकोल बोलस

@iammilind: हाँ। कुछ समय के लिए, हम यह मान सकते हैं।
नवाज

@ निचलोलस: समय के लिए, हम मान सकते हैं कि लैम्ब्डा बिल्कुल एक तर्क लेता है।
नवाज

जवाबों:


160

मजेदार, मैंने सिर्फ C ++ 0x में एक लैम्ब्डा पर एक टेम्पलेट पर विशेषज्ञता के आधार पर एक function_traitsकार्यान्वयन लिखा है जो पैरामीटर प्रकार दे सकता है। चाल, जैसा कि उस प्रश्न के उत्तर में वर्णित है, लैम्बडा का उपयोग करना है । decltypeoperator()

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

// test code below:
int main()
{
    auto lambda = [](int i) { return long(i*10); };

    typedef function_traits<decltype(lambda)> traits;

    static_assert(std::is_same<long, traits::result_type>::value, "err");
    static_assert(std::is_same<int, traits::arg<0>::type>::value, "err");

    return 0;
}

ध्यान दें कि यह समाधान जेनेरिक लैम्ब्डा की तरह काम नहीं करता है[](auto x) {}


हे, मैं सिर्फ यह लिख रहा था। tuple_elementहालांकि, धन्यवाद के बारे में नहीं सोचा था ।
GManNickG

@ मन: यदि आपका दृष्टिकोण इसके समान नहीं है, तो कृपया इसे पोस्ट करें। मैं इस समाधान का परीक्षण करने जा रहा हूं।
नवाज

3
एक पूर्ण विशेषता गैर- के लिए एक विशेषज्ञता का भी उपयोग करेगी const, उन लंबो के लिए घोषित mutable( []() mutable -> T { ... })।
ल्यूक डैंटन

1
@ और यह है कि फ़ंक्शन ऑब्जेक्ट्स के साथ एक मूलभूत समस्या है जो (संभावित) operator()इस कार्यान्वयन के साथ कई ओवरलोड हैं । autoएक प्रकार नहीं है, इसलिए यह कभी भी इसका उत्तर नहीं हो सकता हैtraits::template arg<0>::type
Caleth

1
@helmesjo sf.net/p/tacklelib/tacklelib/HEAD/tree/trunk/include/tacklelib/… टूटे लिंक के समाधान के रूप में: रूट से खोजने की कोशिश करें, ल्यूक।
एंड्री

11

हालांकि मुझे यकीन नहीं है कि यह कड़ाई से मानक अनुरूप है, विचारधारा ने निम्नलिखित कोड संकलित किया है:

template< class > struct mem_type;

template< class C, class T > struct mem_type< T C::* > {
  typedef T type;
};

template< class T > struct lambda_func_type {
  typedef typename mem_type< decltype( &T::operator() ) >::type type;
};

int main() {
  auto l = [](int i) { return long(i); };
  typedef lambda_func_type< decltype(l) >::type T;
  static_assert( std::is_same< T, long( int )const >::value, "" );
}

हालाँकि, यह केवल फ़ंक्शन प्रकार प्रदान करता है, इसलिए परिणाम और पैरामीटर प्रकारों को इसमें से निकाला जाना है। यदि आप उपयोग कर सकते हैं boost::function_traits, result_typeऔर arg1_type उद्देश्य को पूरा करेंगे। चूंकि ideone C ++ 11 मोड में बढ़ावा देने के लिए नहीं लगता है, मैं वास्तविक कोड पोस्ट नहीं कर सका, क्षमा करें।


1
मुझे लगता है, यह एक अच्छी शुरुआत है। उसके लिए +1। अब हमें आवश्यक जानकारी निकालने के लिए फ़ंक्शन प्रकार पर काम करने की आवश्यकता है। (मैं अब बूस्ट का उपयोग नहीं करना चाहता, क्योंकि मैं सामान सीखना चाहता हूं )।
नवाज

6

@KennyTMs उत्तर में दर्शाई गई विशेषज्ञता पद्धति को सभी मामलों को कवर करने के लिए बढ़ाया जा सकता है, जिसमें वैरेडिक और म्यूटेबल लॉड्रिड शामिल हैं:

template <typename T>
struct closure_traits : closure_traits<decltype(&T::operator())> {};

#define REM_CTOR(...) __VA_ARGS__
#define SPEC(cv, var, is_var)                                              \
template <typename C, typename R, typename... Args>                        \
struct closure_traits<R (C::*) (Args... REM_CTOR var) cv>                  \
{                                                                          \
    using arity = std::integral_constant<std::size_t, sizeof...(Args) >;   \
    using is_variadic = std::integral_constant<bool, is_var>;              \
    using is_const    = std::is_const<int cv>;                             \
                                                                           \
    using result_type = R;                                                 \
                                                                           \
    template <std::size_t i>                                               \
    using arg = typename std::tuple_element<i, std::tuple<Args...>>::type; \
};

SPEC(const, (,...), 1)
SPEC(const, (), 0)
SPEC(, (,...), 1)
SPEC(, (), 0)

डेमो

ध्यान दें कि aradic operator()s के लिए arity को समायोजित नहीं किया गया है । इसके बजाय कोई भी विचार कर सकता है is_variadic


1

@KennyTMs द्वारा प्रदान किया गया उत्तर बहुत अच्छा काम करता है, हालाँकि अगर लैम्बडा का कोई पैरामीटर नहीं है, तो इंडेक्स arg <0> का उपयोग करना संकलन नहीं करता है। अगर किसी और को यह समस्या हो रही है, तो मेरे पास एक सरल समाधान है (SFINAE संबंधित समाधानों का उपयोग करने की तुलना में सरल है, वह है)।

बस वैरिएड तर्क प्रकारों के बाद arg संरचना में tuple के अंत में शून्य जोड़ें। अर्थात

template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...,void>>::type type;
    };

चूँकि arty टेम्पलेट मापदंडों की वास्तविक संख्या पर निर्भर नहीं है, वास्तविक गलत नहीं होगा, और अगर यह 0 है तो कम से कम arg <0> अभी भी मौजूद रहेगा और आप इसके साथ वही कर सकते हैं जो आप करेंगे। यदि आप पहले से ही सूचकांक को पार नहीं करने की योजना बना रहे हैं, arg<arity-1>तो इसे आपके वर्तमान कार्यान्वयन में हस्तक्षेप नहीं करना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.