ল্যাম্বডায় প্যারামিটারের ধরন এবং রিটার্নের ধরণটি বের করা কি সম্ভব?


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ভিতরে অবজেক্টটি তৈরি করতে চাই (উপরে দেখানো হয়েছে)।


আপনি প্যারামিটার প্রকার তারপর জানেন তাহলে এই রিটার্ন টাইপ জিনিসটা ব্যবহার করা যাবে। আমি জানি না কীভাবে পরামিতি টাইপটি বের করতে হবে I
মানকারে

এটা কি ধরে নেওয়া হয় যে ফাংশনটি একক যুক্তি নেয়?
iammilind

1
"প্যারামিটারের ধরণ" তবে একটি স্বেচ্ছাসেবী ল্যাম্বদা ফাংশনে প্যারামিটারের ধরণ থাকে না। এটি যে কোনও সংখ্যক পরামিতি নিতে পারে। সুতরাং যে কোনও বৈশিষ্ট্য শ্রেণীর অবস্থান সূচকগুলি দ্বারা প্যারামিটারগুলি অনুসন্ধান করার জন্য ডিজাইন করা উচিত।
নিকল বোলাস

@ আইয়ামিলিন্ড: হ্যাঁ আপাতত, আমরা এটি ধরে নিতে পারি।
নওয়াজ

@ নিকলবোলাস: আপাতত, আমরা ধরে নিতে পারি যে ল্যাম্বদা ঠিক একটি যুক্তি নিয়েছে।
নওয়াজ

উত্তর:


160

মজার, আমি সবেমাত্র একটি লিখেছি function_traits C ++ 0x এ ল্যাম্বডায় একটি টেম্পলেট বিশেষায়নের ভিত্তিতে বাস্তবায়ন যা প্যারামিটারের প্রকারগুলি দিতে পারে। কৌতুক, যে প্রশ্নে উত্তর বর্ণনা অনুযায়ী, ব্যবহার করা হয় ল্যামডা এর । 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ধন্যবাদ, যদিও সম্পর্কে চিন্তা না ।
GManNGG

@ জিএমান: আপনার দৃষ্টিভঙ্গি যদি ঠিক এর মতো না হয় তবে দয়া করে এটি পোস্ট করুন। আমি এই সমাধান পরীক্ষা করতে যাচ্ছি।
নওয়াজ

3
একটি সম্পূর্ণ বৈশিষ্ট্য অ-এর জন্য একটি বিশেষীকরণ ব্যবহার করবে const, ঘোষিত ল্যাম্বদা mutable( []() mutable -> T { ... }) বলে for
লুক ড্যান্টন

1
@ এন্ড্রি হ'ল ফাংশন অবজেক্টগুলির সাথে এটি একটি মৌলিক সমস্যা operator()যা এই বাস্তবায়নের সাথে নয় এমন একাধিক ওভারলোড (সম্ভাব্য) । autoএটি কোনও ধরণের নয়, তাই এটির উত্তর কখনই হতে পারে নাtraits::template arg<0>::type
ক্যালেথ

1
@ হেলমেজো এসএফ.এন.পি. / ট্যাক্লেলিব / ট্যাক্লেলিব / হাইড / ট্র্রি / ট্রাঙ্ক / ইনক্লিনড / ট্যাক্লেলিব/… ভাঙা লিঙ্কগুলির সমাধান হিসাবে: মূল থেকে অনুসন্ধান করার চেষ্টা করুন, লূক।
অ্যান্ড্রি

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 উদ্দেশ্যটি পূরণ করবেন। যেহেতু আইডিয়োন সি ++ 11 মোডে উত্সাহ সরবরাহ করে না বলে মনে হয়, তাই আমি আসল কোডটি পোস্ট করতে পারিনি, দুঃখিত।


1
আমি মনে করি, এটি একটি ভাল শুরু। তার জন্য +1। প্রয়োজনীয় তথ্যগুলি বের করার জন্য এখন আমাদের ফাংশনের ধরণের কাজ করা উচিত। (আমি এখন পর্যন্ত বুস্টটি ব্যবহার করতে চাই না, যেমন আমি স্টাফগুলি শিখতে চাই )।
নওয়াজ

6

@ কেনেটিএম এর উত্তরে দেখানো বিশেষায়নের পদ্ধতিটি ভেরিয়াদিক এবং মিউটেবল ল্যাম্বডাসহ সমস্ত ক্ষেত্রে কভার করার জন্য বাড়ানো যেতে পারে:

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)

ডেমো

নোট করুন যে আরটিটি ভেরিয়াদিক এসগুলির জন্য সামঞ্জস্য করা হয়নি operator()। পরিবর্তে এক বিবেচনা করতে পারেন is_variadic


1

@ কেনেটিএম দ্বারা সরবরাহিত উত্তরটি দুর্দান্ত কাজ করে, তবে কোনও ল্যাম্বডায় কোনও পরামিতি না থাকলে সূচী আর্গ <0> ব্যবহার করে সংকলন হয় না। অন্য কারও যদি সমস্যা হয় তবে আমার একটি সহজ সমাধান রয়েছে (এসফিনএই সম্পর্কিত সমাধানগুলি ব্যবহার করার চেয়ে সহজ, এটি)।

বৈকল্পিক আর্গুমেন্ট প্রকারের পরে আরগ স্ট্রাক্টে টিপলের শেষে কেবল অকার্যকর যুক্ত করুন। অর্থাত

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

যেহেতু আর্টিটি টেম্পলেট প্যারামিটারগুলির প্রকৃত সংখ্যার উপর নির্ভর করে না, প্রকৃতটি ভুল হবে না এবং যদি 0 হয় তবে কমপক্ষে আরগ <0> এখনও উপস্থিত থাকবে এবং আপনি যা করতে চান এটি দিয়ে আপনি এটি করতে পারেন। আপনি যদি ইতিমধ্যে সূচকে অতিক্রম না করার পরিকল্পনা করেন arg<arity-1>তবে এটি আপনার বর্তমান বাস্তবায়নে হস্তক্ষেপ করবে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.