স্টাড :: ফাংশন এবং এসটিডি :: বাইন্ড: সেগুলি কী এবং কখন তাদের ব্যবহার করা উচিত?


127

আমি জানি যে ফান্টেক্টরগুলি কী এবং কখন তাদের stdঅ্যালগোরিদমগুলি সহ ব্যবহার করতে হয় , তবে স্ট্রস্ট্রুপ তাদের সম্পর্কে C ++ 11 এফএকিউতে কী বলে তা আমি বুঝতে পারি নি ।

কেউ কখন কী কী std::bindএবং কী কী std::function, কখন তাদের ব্যবহার করা উচিত তা ব্যাখ্যা করতে পারে এবং নতুনদের জন্য কিছু উদাহরণ দিতে পারে?

উত্তর:


200

std::bindজন্য আংশিক ফাংশন আবেদন

অর্থাৎ, ধরুন আপনার কাছে একটি ফাংশন অবজেক্ট রয়েছে fযা 3 টি আর্গুমেন্ট গ্রহণ করে:

f(a,b,c);

আপনি একটি নতুন ফাংশন অবজেক্ট চান যা কেবলমাত্র দুটি আর্গুমেন্ট গ্রহণ করে, এটি হিসাবে সংজ্ঞায়িত:

g(a,b) := f(a, 4, b);

gফাংশনটির একটি "আংশিক অ্যাপ্লিকেশন" f: মাঝামাঝি যুক্তি ইতিমধ্যে নির্দিষ্ট করা হয়েছে, এবং আরও দুটি বাকি আছে।

আপনি এটি std::bindপেতে ব্যবহার করতে পারেন g:

auto g = bind(f, _1, 4, _2);

এটি করার জন্য কোনও ফান্টেক্টর ক্লাস লেখার চেয়ে এটি আরও সংক্ষিপ্ত।

আপনি যে নিবন্ধটি লিঙ্ক করেছেন তার আরও উদাহরণ রয়েছে। আপনি যখন কোনও অ্যালগরিদমে কোনও ফান্টর পাস করার প্রয়োজন হয় আপনি সাধারণত এটি ব্যবহার করেন। আপনার কাছে একটি ফাংশন বা ফান্টেক্টর রয়েছে যা প্রায়শই আপনি চান কাজটি করেন তবে অ্যালগোরিদম ব্যবহারের চেয়ে বেশি কনফিগারযোগ্য (যেমন আরও পরামিতি রয়েছে)। সুতরাং আপনি কিছু প্যারামিটারগুলিতে যুক্তিগুলি আবদ্ধ করেন, এবং বাকিটি পূরণ করতে অ্যালগরিদমের জন্য রেখে যান:

// raise every value in vec to the power of 7
std::transform(vec.begin(), vec.end(), some_output, std::bind(std::pow, _1, 7));

এখানে, powদুটি পরামিতি লাগে এবং যে কোনও শক্তিতে বাড়িয়ে তুলতে পারে তবে আমরা যা যত্ন করি সেগুলি 7 এর পাওয়ারে বাড়ানো হয়।

একটি অনিয়মিত ব্যবহার যা আংশিক ফাংশন অ্যাপ্লিকেশন নয়, bindএছাড়াও কোনও ক্রিয়াকলাপে যুক্তিগুলিকে পুনরায় অর্ডার করতে পারে:

auto memcpy_with_the_parameters_in_the_right_flipping_order = bind(memcpy, _2, _1, _3);

আপনি এপিআই পছন্দ করেন না বলেই আমি এটি ব্যবহার করার পরামর্শ দিচ্ছি না তবে এর সম্ভাব্য ব্যবহারিক ব্যবহার রয়েছে উদাহরণস্বরূপ:

not2(bind(less<T>, _2, _1));

কম-বা-সমান ক্রিয়াকলাপ (মোট ক্রমটি অনুমান করে, বেলা বেলা)। এই উদাহরণটি সাধারণত প্রয়োজন হয় না কারণ std::less_equalএটি ইতিমধ্যে একটি রয়েছে (এটি <=অপারেটরটির পরিবর্তে ব্যবহার করে <, সুতরাং যদি তারা সামঞ্জস্য না করে তবে আপনার এটি প্রয়োজন হতে পারে, এবং আপনার ক্লাসের লেখককে একটি ক্লাস্টিক সহ দেখতেও যেতে পারে)। যদিও আপনি প্রোগ্রামিংয়ের একটি কার্যকরী শৈলী ব্যবহার করছেন তবে তা রূপান্তরটির ধরণের।


18
সদস্য ফাংশনে কলব্যাকের myThread=boost::thread(boost::bind(&MyClass::threadMain, this))
জন্যও

15
বাঁধার চমৎকার ব্যাখ্যা। তবে কি std::function?
রেডএক্স

10
আপনার powউদাহরণটি সংকলন করে না। যেহেতু powএকটি ওভারলোডেড ফাংশন, আপনাকে কোন ওভারলোড নিজেই নির্দিষ্ট করতে হবে। বাইন্ডিং এটিকে ফলাফল ফান্টারের কলার দ্বারা ছাড় দিতে পারে না। উদাstd::transform(vec.begin(), vec.end(), out.begin(), std::bind((double (*)(double, int))std::pow, _1, 7));
এমএম

2
খুব ভালভাবে ব্যাখ্যা করা হয়েছে, তবে কখনও কখনও দ্বিতীয় যুক্তি হিসাবে ব্যবহারের std::bindসাথে একত্রিত হয় this। আপনি দয়া করে এই ব্যবহারের ক্ষেত্রে বিস্তারিত বলতে পারেন?
মেন্ডেস

2
এছাড়াও "_1" দ্বারা আপনি বোঝাতে চাইছেন std::placeholders::_1। কেন এটি সংকলন করছে না তা জানতে আমাকে কিছুক্ষণ সময় নিলেন।
টেরিগ করুন

25

স্ট্যান্ড :: ফাংশন এবং স্ট্যান্ড :: বাইন্ডের অন্যতম প্রধান ব্যবহার আরও জেনারেলাইজড ফাংশন পয়েন্টার। আপনি এটি কলব্যাক প্রক্রিয়াটি প্রয়োগ করতে ব্যবহার করতে পারেন। জনপ্রিয় দৃশ্যের একটি হ'ল আপনার কিছু ফাংশন রয়েছে যা কার্যকর করতে দীর্ঘ সময় নিতে চলেছে তবে আপনি এটির প্রত্যাবর্তনের জন্য অপেক্ষা করতে চান না তবে আপনি সেই ফাংশনটি পৃথক থ্রেডে চালাতে পারেন এবং এটি একটি ফাংশন পয়েন্টার দিতে পারেন যে এটি হবে এটি সম্পূর্ণ হওয়ার পরে কলব্যাক।

এটি কীভাবে ব্যবহার করবেন সে জন্য এখানে একটি নমুনা কোড রয়েছে:

class MyClass {
private:
    //just shorthand to avoid long typing
    typedef std::function<void (float result)> TCallback;

    //this function takes long time
    void longRunningFunction(TCallback callback)
    {
        //do some long running task
        //...
        //callback to return result
        callback(result);
    }

    //this function gets called by longRunningFunction after its done
    void afterCompleteCallback(float result)
    {
        std::cout << result;
    }

public:
    int longRunningFunctionAsync()
    {
        //create callback - this equivalent of safe function pointer
        auto callback = std::bind(&MyClass::afterCompleteCallback, 
            this, std::placeholders::_1);

        //normally you want to start below function on seprate thread, 
        //but for illustration we will just do simple call
        longRunningFunction(callback);
    }
};

5
এটি একটি দুর্দান্ত উত্তর। আমি এই উত্তরটি খুঁজতে সমস্ত দিকে নজর রেখেছি। ধন্যবাদ @ শীতলশাহ
16

বাঁধাই কেন এটি নিরাপদ করতে সহায়তা করে তার জন্য আপনি একটি ব্যাখ্যা যুক্ত করতে পারেন?
স্টিভেন লু

আমার খারাপ ... আমি এটি আরও "নিরাপদ" বলার ইচ্ছা করি নি। সাধারণ ফাংশন পয়েন্টারগুলিও টাইপসেফ তবে স্ট্যান্ড :: ফাংশনটি ল্যাম্বডাস, প্রসঙ্গ ক্যাপচার, সদস্য পদ্ধতি ইত্যাদির সাথে কাজ করা আরও জেনারেল
শীতল শাহ

বাইন্ড (& মাইক্লাস :: আফটার কমপ্লিটক্যালব্যাক, এটি, স্টাড :: স্থানধারক :: _ 1), সংজ্ঞায়িত 1 এর জন্য 2 টি আর্গ, অকার্যকর কমপ্লিটক্যালব্যাক (ভাসমান ফলাফল), এটি ব্যাখ্যা করতে পারে?
ননক করুন

1
@ ননক সদস্য ফাংশনের ফাংশন পয়েন্টারগুলির জন্য, আমাদের প্রথম আর্গুমেন্ট হিসাবে "এই" পয়েন্টারটি পাস করতে হবে।
সানোজ সুবরণ

12

স্ট্যান্ড :: বাইন্ডকে বুস্ট বাইন্ড অন্তর্ভুক্ত করার প্রস্তাবের পরে লাইব্রেরিতে ভোট দেওয়া হয়েছিল, প্রাথমিকভাবে এটি আংশিক ফাংশন বিশেষীকরণ যেখানে আপনি কয়েকটি প্যারামিটারগুলি ঠিক করতে এবং ফ্লাইতে অন্যকে পরিবর্তন করতে পারেন। এখন এটি সি ++ এ ল্যাম্বডাস করার লাইব্রেরি পদ্ধতি। উত্তর হিসাবে স্টিভ জেসোপ

এখন যে সি ++ 11 ল্যাম্বডা ফাংশন সমর্থন করে আমি এখন আর স্ট্যান্ড :: বাইন্ড ব্যবহার করার কোন প্রলোভন অনুভব করি না। আমি লাইব্রেরি বৈশিষ্ট্যের চেয়ে ভাষা বৈশিষ্ট্য সহ কারিঙ (আংশিক বিশেষীকরণ) ব্যবহার করব।

std :: ফাংশন অবজেক্টস হল বহুকোষী ফাংশন। মূল ধারণাটি হ'ল সমস্ত কলযোগ্য অবজেক্টগুলি আন্তঃবিনে পরিবর্তন করতে সক্ষম হয়।

আরও তথ্যের জন্য আমি আপনাকে এই দুটি লিঙ্কে নির্দেশ করব:

সি ++ 11 এ ল্যাম্বদা ফাংশন: http://www.nullptr.me/2011/10/12/c11-lambda-having-fun-with-brackets/#.UJmXu8XA9Z8

সি ++ এ কল করার যোগ্য সত্তা: http://www.nullptr.me/2011/05/31/callable-entity/#.UJmXuMXA9Z8


5
std::bindল্যাম্বডাস ছাড়া কখনই অস্তিত্ব ছিল না - এই দুটি বৈশিষ্ট্যই সি ++ 11-এ প্রবর্তিত হয়েছিল। আমাদের কাছে bind1stএবং bind2ndযা ছিল সি ++ 11 বাইন্ডের ইমেলিত সংস্করণ।
এমএম

5

সি ++ এ প্লাগইন থ্রেড পুল তৈরি করতে আমি এটি দীর্ঘ সময় ব্যবহার করেছি; যেহেতু ফাংশনটি তিনটি প্যারামিটার নিয়েছে আপনি এটি লিখতে পারেন

মনে করুন আপনার পদ্ধতিতে স্বাক্ষর রয়েছে:

int CTask::ThreeParameterTask(int par1, int par2, int par3)

তিনটি পরামিতি আবদ্ধ করতে একটি ফাংশন অবজেক্ট তৈরি করতে আপনি এটি করতে পারেন

// a template class for converting a member function of the type int function(int,int,int)
//to be called as a function object
template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
class mem_fun3_t
{
public:
    explicit mem_fun3_t(_Ret (_Class::*_Pm)(_arg1,_arg2,_arg3))
        :m_Ptr(_Pm) //okay here we store the member function pointer for later use
    {}

    //this operator call comes from the bind method
    _Ret operator()(_Class *_P, _arg1 arg1, _arg2 arg2, _arg3 arg3) const
    {
        return ((_P->*m_Ptr)(arg1,arg2,arg3));
    }
private:
    _Ret (_Class::*m_Ptr)(_arg1,_arg2,_arg3);// method pointer signature
};

এখন, পরামিতিগুলি আবদ্ধ করতে, আমাদের একটি বাইন্ডার ফাংশন লিখতে হবে। সুতরাং, এখানে এটি যায়:

template<typename _Func,typename _Ptr,typename _arg1,typename _arg2,typename _arg3>
class binder3
{
public:
    //This is the constructor that does the binding part
    binder3(_Func fn,_Ptr ptr,_arg1 i,_arg2 j,_arg3 k)
        :m_ptr(ptr),m_fn(fn),m1(i),m2(j),m3(k){}


        //and this is the function object 
        void operator()() const
        {
            m_fn(m_ptr,m1,m2,m3);//that calls the operator
        }
private:
    _Ptr m_ptr;
    _Func m_fn;
    _arg1 m1; _arg2 m2; _arg3 m3;
};

এবং, বাইন্ডার 3 শ্রেণি - বাইন্ড 3 ব্যবহার করতে একটি সহায়ক ফাংশন:

//a helper function to call binder3
template <typename _Func, typename _P1,typename _arg1,typename _arg2,typename _arg3>
binder3<_Func, _P1, _arg1, _arg2, _arg3> bind3(_Func func, _P1 p1,_arg1 i,_arg2 j,_arg3 k)
{
    return binder3<_Func, _P1, _arg1, _arg2, _arg3> (func, p1,i,j,k);
}

এবং এখানে এটি কল কিভাবে আমাদের

F3 f3 = PluginThreadPool::bind3( PluginThreadPool::mem_fun3( 
          &CTask::ThreeParameterTask), task1,2122,23 );

দ্রষ্টব্য: f3 (); পদ্ধতিটি কল করবে টাস্ক 1-> থ্রিপ্যারামিটার টাস্ক (21,22,23);

আরও বেহাল বিবরণ জন্য -> http://www.codeproject.com/Articles/26078/AC-

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