সি ++ ফান্টেক্টর এবং তার ব্যবহারগুলি কী কী?


875

আমি সি ++ তে ফ্যান্টরস সম্পর্কে প্রচুর শুনছি। তারা কি এবং কোন ক্ষেত্রে তারা কার্যকর হবে সে সম্পর্কে কেউ আমাকে একটি ওভারভিউ দিতে পারে?


4
এই প্রশ্নের উত্তরের বিষয়ে এই বিষয়টি আচ্ছাদিত করা হয়েছে: স্ট্যাকওভারফ্লো
কেন- ওভাররাইড- কপিরেটর #

2
এটি সি ++ এ ক্লোজার তৈরি করতে ব্যবহৃত হয়।
তামার.হাট

নীচের উত্তরগুলির দিকে তাকিয়ে যদি কেউ ভাবছেন যে এর operator()(...)অর্থ কী: এটি "ফাংশন কল" অপারেটরটিকে ওভারলোড করছে । এটি কেবল অপারেটরের জন্য অপারেটর ওভারলোডিং ()operator()কল করা কোনও ফাংশন কল করতে ভুল করবেন না operator, তবে এটি সাধারণ অপারেটর হিসাবে ওভারলোডিং সিনট্যাক্স হিসাবে দেখুন।
জর্দোশত

উত্তর:


1041

একজন ফান্টেক্টর হ'ল একটি শ্রেণি যা অপারেটর () কে সংজ্ঞায়িত করে। এটি আপনাকে এমন কোনও বস্তু তৈরি করতে দেয় যা কোনও ফাংশন "দেখতে" দেখায়:

// this is a functor
struct add_x {
  add_x(int val) : x(val) {}  // Constructor
  int operator()(int y) const { return x + y; }

private:
  int x;
};

// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument

std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element 
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 
assert(out[i] == in[i] + 1); // for all i

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

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

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


32
আপনি কি এই লাইনটি ব্যাখ্যা করতে পারেন, দয়া করে std :: রূপান্তর (in.begin (), in.end (), out.begin (), add_x (1)); আপনি সেখানে কেন add_x লিখছেন, অ্যাড 42 নয়?
এলেকস

102
@ অ্যালেক্স দু'জনেই কাজ করতেন (তবে এর প্রভাবটি অন্যরকম হত)। আমি যদি ব্যবহার add42করতাম তবে আমি আগে তৈরি করা ফান্টেক্টরটি ব্যবহার করে প্রত্যেকটি মানতে 42 টি যুক্ত করতাম। সঙ্গে add_x(1)আমি functor, এক যা শুধুমাত্র প্রতিটি মান 1 যোগ করে একটি নতুন দৃষ্টান্ত তৈরি করুন। এটি সহজভাবে দেখানো হয় যে প্রায়শই আপনি প্রথমে এটি তৈরির পরিবর্তে এবং প্রয়োজনে কোনও কিছুর জন্য ব্যবহার করার আগে যখন এটি প্রয়োজন হয় তখন "ফ্লাইয়ের উপরে" ফান্টারটি ইনস্ট্যান্ট করেন।
jalf

8
@ জাজান অবশ্যই। তাদের কেবল আছে operator(), কারণ কলার এটি করতে অনুরোধ জানায়। কি আর functor সদস্য ফাংশন, কনস্ট্রাকটর, অপারেটর ও সদস্য ভেরিয়েবল হয়েছে সম্পূর্ণরূপে আপনি আপ হয়।
জলফ

4
@ rikimaru2013 ফাংশনাল প্রোগ্রামিংয়ের পার্লেন্সে, আপনি সঠিক, একটি ফাংশন একটি ফান্টেক্টর, তবে সি ++ এর পার্লেন্সে, ফ্যান্টেক্টরটি বিশেষত একটি ফাংশন হিসাবে ব্যবহৃত একটি শ্রেণি। পরিভাষাটি প্রথম দিকে কিছুটা আপত্তিজনকভাবে ব্যবহার করা হয়েছিল, তবে বিভাগটি কার্যকর পার্থক্য এবং তাই আজও বজায় রয়েছে। আপনি যদি C ++ প্রসঙ্গে ফাংশনগুলিকে "ফান্টেক্টর" হিসাবে উল্লেখ করা শুরু করেন তবে আপনি কেবল কথোপকথনকে বিভ্রান্ত করবেন।
এসআরএম

6
এটি কোন শ্রেণি বা শ্রেণীর উদাহরণ? বেশিরভাগ উত্সগুলিতে, add42তাকে ফান্টেক্টর বলা হবে, এটি নয় add_x(যা ফান্টারের ক্লাস বা কেবল ফান্টারের ক্লাস)। আমি সেই পরিভাষাটিকে সামঞ্জস্যপূর্ণ বলে মনে করি কারণ ফান্টেক্টরগুলিকে ফাংশন ক্লাস নয়, ফাংশন অবজেক্টও বলা হয় । আপনি এই বিষয়টি পরিষ্কার করতে পারেন?
সের্গেই টেচেনভ

121

সামান্য সংযোজন। আপনি এর boost::functionমতো ফাংশন এবং পদ্ধতিগুলি থেকে ফান্ট্যাকার তৈরি করতে ব্যবহার করতে পারেন :

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

এবং আপনি এই ফান্টারে স্টেট যুক্ত করতে বুস্ট :: বাইন্ড ব্যবহার করতে পারেন

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

এবং সবচেয়ে কার্যকর, বুস্ট :: বাইন্ড অ্যান্ড বুস্ট :: ফাংশন সহ আপনি ক্লাস পদ্ধতি থেকে ফান্টর তৈরি করতে পারেন, এটি আসলে একজন প্রতিনিধি:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

আপনি ফান্টেক্টরগুলির তালিকা বা ভেক্টর তৈরি করতে পারেন

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

এই সমস্ত জিনিস নিয়ে একটি সমস্যা আছে, সংকলক ত্রুটি বার্তাগুলি মানব পাঠযোগ্য নয় :)


4
operator ()ক্লাসগুলি ব্যক্তিগত থেকে ডিফল্ট হওয়ার পরে আপনার প্রথম উদাহরণে প্রকাশ্য হওয়া উচিত নয় ?
নাথান অলিভার

4
হয়তো কোনও সময়ে এই উত্তরটি আপডেটের দাবি রাখে, যেহেতু এখন থেকে
লাম্বডাস

102

ফান্টেক্টর এমন একটি বস্তু যা কোনও ফাংশনের মতো কাজ করে। মূলত, একটি শ্রেণি যা সংজ্ঞায়িত করে operator()

class MyFunctor
{
   public:
     int operator()(int x) { return x * 2;}
}

MyFunctor doubler;
int x = doubler(5);

আসল সুবিধা হ'ল কোনও ফান্টেক্টর রাষ্ট্র ধরে রাখতে পারে।

class Matcher
{
   int target;
   public:
     Matcher(int m) : target(m) {}
     bool operator()(int x) { return x == target;}
}

Matcher Is5(5);

if (Is5(n))    // same as if (n == 5)
{ ....}

11
কেবল এগুলি যুক্ত করা দরকার যে সেগুলি কেবল ফাংশন পয়েন্টারের মতো ব্যবহার করা যেতে পারে।
মার্টিন ইয়র্ক

7
@ লোকিস্টারি - ধারণাটিতে নতুন যারা তাদের জন্য এটি কিছুটা বিভ্রান্তিকর হতে পারে। ফ্যাক্টরগুলি "ফাংশন পয়েন্টারগুলির স্থানে" তবে "সদৃশ" ব্যবহার করা যেতে পারে। উদাহরণস্বরূপ, ফাংশন পয়েন্টার গ্রহণকারী কোনও ফাংশন তার জায়গায় কোনও ফান্টর নিতে পারে না এমনকি ফান্টারের ফাংশন পয়েন্টার হিসাবে একই আর্গুমেন্ট এবং রিটার্ন মান থাকলেও। নকশা করার সময় এবং বৃহত্তর, ফান্ট্যাকাররা পছন্দসই এবং তাত্ত্বিকভাবে "আরও আধুনিক" যাওয়ার উপায়।
ম্যাসনউইনসৌয়ার

দ্বিতীয়টি কেন ফিরে আসবে intযখন ফিরে আসে bool? এটি সি ++, সি নয়, যখন এই উত্তরটি লেখা হয়েছিল তখন boolউপস্থিত ছিল না?
মনিকার মোকদ্দমাটি

@ কিপ্যায়েট্যাক্সেস আমার একটি টাইপোর অনুমান। আমি সম্ভবত প্রথম উদাহরণটি থেকে কোডটি অনুলিপি করেছি এবং এটি পরিবর্তন করতে ভুলে গিয়েছি। আমি এখন এটি স্থির করেছি।
জেমস কারান

1
@ রিয়াসাত যদি ম্যাচার একটি লাইব্রেরিতে থাকে তবে ইস 5 () সংজ্ঞা দেওয়া খুব সহজ। আপনি ইস 7 (), ইস32 () ইত্যাদি তৈরি করতে পারেন, এটি কেবল একটি উদাহরণ। এই ফান্টার আরও জটিল হতে পারে।
জেমস কারান

51

নাম "ফান্টার" দৃশ্যে সি ++ হাজির হওয়ার অনেক আগে থেকেই বিভাগের তত্ত্বে প্রচলিত ছিল । এটি ফান্টারের সি ++ ধারণার সাথে কোনও সম্পর্ক নেই। আমরা C ++ এ "ফান্টেক্টর" বলি তার পরিবর্তে নাম ফাংশন অবজেক্টটি ব্যবহার করা ভাল । এইভাবে অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজগুলি অনুরূপ নির্মাণকে কল করে।

প্লেইন ফাংশনের পরিবর্তে ব্যবহৃত:

বৈশিষ্ট্য:

  • ফাংশন অবজেক্টের স্টেট থাকতে পারে
  • ফাংশন অবজেক্টটি ওওপি-তে ফিট করে (এটি অন্য প্রতিটি বস্তুর মতো আচরণ করে)।

কনস:

  • প্রোগ্রামটিতে আরও জটিলতা নিয়ে আসে।

ফাংশন পয়েন্টারের পরিবর্তে ব্যবহৃত:

বৈশিষ্ট্য:

  • ফাংশন অবজেক্ট প্রায়শই ইনলাইন করা যেতে পারে

কনস:

  • রানটাইম চলাকালীন ফাংশন অবজেক্টটি অন্য ফাংশন অবজেক্ট টাইপের সাথে অদলবদল করা যায় না (কমপক্ষে এটি কোনও বেস ক্লাস প্রসারিত না করে, যার ফলে কিছুটা ওভারহেড দেয়)

ভার্চুয়াল ফাংশন পরিবর্তে ব্যবহৃত:

বৈশিষ্ট্য:

  • ফাংশন অবজেক্ট (নন-ভার্চুয়াল) এর জন্য vtable এবং রানটাইম প্রেরণের প্রয়োজন হয় না, সুতরাং বেশিরভাগ ক্ষেত্রে এটি আরও দক্ষ

কনস:

  • রানটাইম চলাকালীন ফাংশন অবজেক্টটি অন্য ফাংশন অবজেক্ট টাইপের সাথে অদলবদল করা যায় না (কমপক্ষে এটি কোনও বেস ক্লাস প্রসারিত না করে, যার ফলে কিছুটা ওভারহেড দেয়)

1
আপনি কি বাস্তব উদাহরণে এই ব্যবহারের ক্ষেত্রে ব্যাখ্যা করতে পারেন? আমরা কীভাবে পলিমারফিজম অ্যাডন ফানেশন পয়েন্টার হিসাবে ফান্টেক্টর ব্যবহার করতে পারি?
মিলাদ খাজাভি

1
আসলে কী বোঝায় যে কোনও ফান্টার রাষ্ট্র রাখে?
এরোগল

একরকম একাধিক পলিমারফিজম করার জন্য একটি বেস ক্লাসের প্রয়োজন তা উল্লেখ করার জন্য ধন্যবাদ। আমার কেবল সমস্যাটি আছে যে আমাকে একই ফাংশন পয়েন্টার হিসাবে একই জায়গায় একটি ফান্টর ব্যবহার করতে হবে এবং আমি খুঁজে পেলাম যে একমাত্র উপায় ছিল ফান্টিকার বেস ক্লাস (যেমন আমি সি ++ 11 স্টাফ ব্যবহার করতে পারি না) লিখি write আমি নিশ্চিত আপনার উত্তরটি না পড়া পর্যন্ত এই ওভারহেডটি বোঝা যায় কিনা তা নিশ্চিত হন।
idclev 463035818

1
@Erogol একটি functor একটি বস্তু যা সিনট্যাক্স সমর্থন করার জন্য এরকম foo(arguments)। সুতরাং, এতে ভেরিয়েবল থাকতে পারে; উদাহরণস্বরূপ, যদি আপনার কোনও update_password(string)ফাংশন থাকে, তবে আপনি সম্ভবত এটি ঘটতে পারেন তার ট্র্যাক রাখতে পারেন; কোনও ফান্টারের সাথে, private long timeএটি সর্বশেষে ঘটে যাওয়া টাইমস্ট্যাম্পের প্রতিনিধিত্ব করতে পারে । একটি ফাংশন পয়েন্টার বা প্লেইন ফাংশন সঙ্গে, আপনি বদলে definition.l দ্বারা তার নামস্থান, যা শুধুমাত্র সরাসরি ডকুমেন্টেশন এবং ব্যবহারের দ্বারা সম্পর্কযুক্ত পরিবর্তনশীল বাইরে ব্যবহার করতে হবে চাই
ফান্ড মনিকা এর মামলা

4
Mentioning উল্লেখ করার জন্য যে নামটি অকারণে তৈরি করা হয়েছে। আমি স্রেফ অনুসন্ধান করছি যে গাণিতিক (বা আপনি চাইলে কার্যকরী) ফান্টেক্টর এবং সি ++ এর সাথে কী সম্পর্ক relation
হাই-এঞ্জেল

41

অন্যদের মতো উল্লেখ করেছেন, ফান্টেক্টর এমন একটি বস্তু যা কোনও ফাংশনের মতো কাজ করে, অর্থাত এটি ফাংশন কল অপারেটরটিকে ওভারলোড করে।

স্ট্যাক্টরগুলি সাধারণত এসটিএল অ্যালগরিদমে ব্যবহৃত হয়। এগুলি কার্যকর কারণ তারা কার্যকরী ভাষায় বন্ধের মতো ফাংশন কলগুলির আগে এবং এর মধ্যে রাষ্ট্র ধরে রাখতে পারে। উদাহরণস্বরূপ, আপনি এমন একটি MultiplyByফান্টকারকে সংজ্ঞায়িত করতে পারেন যা তার যুক্তিকে একটি নির্দিষ্ট পরিমাণ দ্বারা গুণ করে:

class MultiplyBy {
private:
    int factor;

public:
    MultiplyBy(int x) : factor(x) {
    }

    int operator () (int other) const {
        return factor * other;
    }
};

তারপরে আপনি MultiplyByস্ট্যান্ড :: ট্রান্সফর্মের মতো একটি অ্যালগরিদমে কোনও বস্তুটি পাস করতে পারেন :

int array[5] = {1, 2, 3, 4, 5};
std::transform(array, array + 5, array, MultiplyBy(3));
// Now, array is {3, 6, 9, 12, 15}

কোনও ফাংশনটির পয়েন্টারের উপরে ফান্টারের আরও একটি সুবিধা হ'ল কলটি আরও কিছু ক্ষেত্রে ইনলাইন করা যায়। যদি আপনি কোনও ফাংশন পয়েন্টারটিতে পৌঁছে দেন transform, যদি না সেই কলটি ইনলাইন না হয়ে থাকে এবং সংকলকটি জানে না যে আপনি সর্বদা এটিতে একই ফাংশনটি পাস করেন, এটি পয়েন্টারের মাধ্যমে কলটি ইনলাইন করতে পারে না।


37

আমাদের মধ্যে আমার মতো নবাগতদের জন্য: কিছুটা গবেষণা করার পরে আমি বুঝতে পারলাম কোড জাল্ফ পোস্ট করেছে কী করে।

ফ্যান্টেক্টর হ'ল একটি শ্রেণি বা স্ট্রাক্ট অবজেক্ট যা কোনও ফাংশনের মতো "বলা যেতে পারে"। এটি ওভারলোড করে সম্ভব হয়েছে () operator() operator(নিশ্চিত না কি তার বলা হয়) আর্গুমেন্ট যে কোন সংখ্যার গ্রহণ করতে পারেন। অন্যান্য অপারেটর কেবল দুটি গ্রহণ করে অর্থাৎ + operatorদুটি মাত্র মান নিতে পারে (অপারেটরের প্রতিটি পক্ষের একটি) এবং আপনি যে মানটি এর জন্য অতিরিক্ত চাপিয়েছেন তা ফেরত দিতে পারে। আপনি () operatorএটির অভ্যন্তরের যে কোনও সংখ্যক যুক্তি ফিট করতে পারেন যা এটি তার নমনীয়তা দেয়।

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

আমার কোড (আমি জালফের ভেরিয়েবলের নাম গুলিয়ে দেখলাম)

class myFunctor
{ 
    public:
        /* myFunctor is the constructor. parameterVar is the parameter passed to
           the constructor. : is the initializer list operator. myObject is the
           private member object of the myFunctor class. parameterVar is passed
           to the () operator which takes it and adds it to myObject in the
           overloaded () operator function. */
        myFunctor (int parameterVar) : myObject( parameterVar ) {}

        /* the "operator" word is a keyword which indicates this function is an 
           overloaded operator function. The () following this just tells the
           compiler that () is the operator being overloaded. Following that is
           the parameter for the overloaded operator. This parameter is actually
           the argument "parameterVar" passed by the constructor we just wrote.
           The last part of this statement is the overloaded operators body
           which adds the parameter passed to the member object. */
        int operator() (int myArgument) { return myObject + myArgument; }

    private: 
        int myObject; //Our private member object.
}; 

এর মধ্যে যদি কোনও ভুল হয় বা কেবল সরল ভুল নির্দ্বিধায় আমাকে সংশোধন করে!


1
() অপারেটরটিকে ফাংশন-কল অপারেটর বলা হয়। আমার ধারণা আপনি এটিকে প্রথম বন্ধনী অপারেটরও বলতে পারেন।
গৌতম

4
"এই প্যারামিটারটি আসলে আমরা কেবল" হু "লিখেছি কনস্ট্রাক্টর দ্বারা প্রদত্ত" প্যারামিটারভার "যুক্তিটি ?
লাইটনেস রেস

22

ফ্যান্টেক্টর হ'ল একটি অর্ডার ফাংশন যা প্যারামেট্রাইজড (অর্থাত্ টেম্প্লেটেড) ধরণের ক্ষেত্রে একটি ফাংশন প্রয়োগ করে। এটি মানচিত্রের উচ্চতর ক্রমের ক্রিয়াকলাপ। উদাহরণস্বরূপ, আমরা এর জন্য একটি ফান্টর সংজ্ঞায়িত করতে পারি std::vector:

template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
std::vector<U> fmap(F f, const std::vector<T>& vec)
{
    std::vector<U> result;
    std::transform(vec.begin(), vec.end(), std::back_inserter(result), f);
    return result;
}

এই ফাংশনটি একটি লাগে std::vector<T>এবং আয় std::vector<U>যখন একটি ফাংশন দেওয়া Fযে একটি লাগে Tএবং একটি ফেরৎ U। একটি ফান্টারের ধারক প্রকারের তুলনায় সংজ্ঞায়িত করতে হবে না, এটি কোনও টেম্পলেটযুক্ত ধরণের জন্যও সংজ্ঞায়িত করা যেতে পারে std::shared_ptr:

template<class F, class T, class U=decltype(std::declval<F>()(std::declval<T>()))>
std::shared_ptr<U> fmap(F f, const std::shared_ptr<T>& p)
{
    if (p == nullptr) return nullptr;
    else return std::shared_ptr<U>(new U(f(*p)));
}

Heres একটি সাধারণ উদাহরণ যা প্রকারটিকে একটিতে রূপান্তর করে double:

double to_double(int x)
{
    return x;
}

std::shared_ptr<int> i(new int(3));
std::shared_ptr<double> d = fmap(to_double, i);

std::vector<int> is = { 1, 2, 3 };
std::vector<double> ds = fmap(to_double, is);

দুটি আইন রয়েছে যা ফান্ট্যাক্টরদের অনুসরণ করা উচিত। প্রথমটি হ'ল আইডেন্টিটি আইন, যা বলে যে ফান্টরকে যদি একটি পরিচয় ফাংশন দেওয়া হয় তবে এটি পরিচয় ফাংশনটি প্রকারের সাথে প্রয়োগ করার মতো fmap(identity, x)হওয়া উচিত , যা একইরকম হওয়া উচিত identity(x):

struct identity_f
{
    template<class T>
    T operator()(T x) const
    {
        return x;
    }
};
identity_f identity = {};

std::vector<int> is = { 1, 2, 3 };
// These two statements should be equivalent.
// is1 should equal is2
std::vector<int> is1 = fmap(identity, is);
std::vector<int> is2 = identity(is);

পরবর্তী আইনটি কম্পোজিশন আইন, যা বলে যে ফান্টকারকে দুটি ফাংশনের একটি সংমিশ্রণ দেওয়া হয়, তবে এটি প্রথম ফাংশনের জন্য ফান্টার প্রয়োগ করার পরে এবং তারপরে আবার দ্বিতীয় ফাংশনের জন্য একই রকম হওয়া উচিত। সুতরাং, fmap(std::bind(f, std::bind(g, _1)), x)একই হিসাবে হওয়া উচিত fmap(f, fmap(g, x)):

double to_double(int x)
{
    return x;
}

struct foo
{
    double x;
};

foo to_foo(double x)
{
    foo r;
    r.x = x;
    return r;
}

std::vector<int> is = { 1, 2, 3 };
// These two statements should be equivalent.
// is1 should equal is2
std::vector<foo> is1 = fmap(std::bind(to_foo, std::bind(to_double, _1)), is);
std::vector<foo> is2 = fmap(to_foo, fmap(to_double, is));

2
ধারা যে functor তর্ক সঠিকভাবে এই অর্থ ব্যবহার করা উচিত (এছাড়াও দেখুন en.wikipedia.org/wiki/Functor ), এবং যে ফাংশন অবজেক্টের জন্য এটি ব্যবহার ঠিক পঙ্কিল হল: jackieokay.com/2017/01/26/functors.html এটা যদিও এর জন্য খুব দেরী হতে পারে, এখানে উত্তরগুলির সংখ্যা দেওয়া হয়েছে যা কেবলমাত্র ফাংশনটির অর্থ বিবেচনা করে।
আরম্ব

2
এই উত্তরটি> 700 উপবোটগুলির সাথে একটি হওয়া উচিত। যেহেতু কেউ হাস্কেলকে সি ++ এর চেয়ে আরও ভালভাবে জানেন, সি ++ লিঙ্গুয়া আমাকে সর্বদা বিস্মিত করে।
মিসচমিট

বিভাগ তত্ত্ব এবং সি ++? এই বারটোস মাইলিউস্কির গোপন এসও অ্যাকাউন্ট?
মতিন উলহাক

1
এটি স্ট্যান্ডার্ড নোটেশনে ফান্টারের আইনগুলির সংক্ষিপ্তসারে সহায়ক হতে পারে: fmap(id, x) = id(x)এবং fmap(f ◦ g, x) = fmap(f, fmap(g, x))
মতিন উলহাক

@ এমএসএমমিট হ'ল ফান্টেক্টর এর অর্থ এটিও, সি ++ নামটি "ফাংশন অবজেক্ট" হিসাবে একই অর্থ বোঝায়
কালেথ

9

এখানে একটি বাস্তব পরিস্থিতি যেখানে আমার সমস্যা সমাধানের জন্য আমাকে একটি ফান্টেক্টর ব্যবহার করতে বাধ্য করা হয়েছিল:

আমার ফাংশনগুলির একটি সেট রয়েছে (যার মধ্যে 20 টি বলুন) এবং সেগুলি 3 টি নির্দিষ্ট স্পটে আলাদা আলাদা ফাংশন ব্যতীত সমস্তগুলি অভিন্ন।

এটি অবিশ্বাস্য বর্জ্য, এবং কোড সদৃশ। সাধারণত আমি কেবল একটি ফাংশন পয়েন্টারে পাস করব এবং কেবল 3 স্পটে কল করব। (সুতরাং কোডটি বিশ বারের পরিবর্তে একবারে উপস্থিত হওয়া দরকার))

তবে আমি বুঝতে পেরেছি, প্রতিটি ক্ষেত্রে নির্দিষ্ট ফাংশনের জন্য সম্পূর্ণ আলাদা প্যারামিটার প্রোফাইলের প্রয়োজন হয়! কখনও কখনও 2 টি প্যারামিটার, কখনও কখনও 5 পরামিতি ইত্যাদি etc.

আর একটি সমাধান হতে পারে একটি বেস ক্লাস, যেখানে নির্দিষ্ট ফাংশন একটি উত্পন্ন শ্রেণীর মধ্যে একটি ওভাররাইড পদ্ধতি। তবে আমি কি এই প্রকৃতপক্ষে সমস্ত নিখরচায় তৈরি করতে চাই, যাতে আমি কোনও ফাংশন পয়েন্টারটি পাস করতে পারি ????

সমাধান: সুতরাং আমি যা করেছি তা হ'ল আমি একটি মোড়ক ক্লাস তৈরি করলাম (একটি "ফান্টেক্টর") যা আমার প্রয়োজনীয় ফাংশনগুলির কল করতে সক্ষম। আমি এটি আগাম সেট আপ করেছি (এর প্যারামিটারগুলি সহ, ইত্যাদি) এবং তারপরে আমি এটি কোনও ফাংশন পয়েন্টারের পরিবর্তে পাস করি। এখন কল কোডটি ভিতরে কী ঘটছে তা না জেনে ফান্টেক্টরকে ট্রিগার করতে পারে। এমনকি এটি একাধিকবার কলও করতে পারে (আমার কাছে এটি 3 বার কল করার দরকার ছিল))


এটি হ'ল একটি ব্যবহারিক উদাহরণ যেখানে কোনও ফান্ট্যাকার স্পষ্ট এবং সহজ সমাধান হিসাবে প্রমাণিত হয়েছিল, যা আমাকে কোডের নকলকে 20 ফাংশন থেকে 1 এ হ্রাস করতে দিয়েছিল।


3
যদি আপনার ফান্টর বিভিন্ন নির্দিষ্ট ফাংশন বলে, এবং এই অন্যান্য ফাংশনগুলি তারা গ্রহণ করে এমন প্যারামিটারের সংখ্যায় ভিন্ন, তবে এর অর্থ কি আপনার ফান্টার এই অন্যান্য ক্রিয়াকলাপে প্রেরণের জন্য একটি পরিবর্তনশীল সংখ্যক যুক্তি স্বীকার করেছে?
জনবেকার্স

4
আপনি কি দয়া করে কোডের কিছু অংশ উদ্ধৃত করে উপরের পরিস্থিতিটি ব্যাখ্যা করতে পারেন, আমি সি ++ তে নতুন এই ধারণাটি বুঝতে চাই ...
সঞ্জীব

3

কলব্যাক ব্যবহৃত ব্যতীত সি ++ ফান্ট্যাক্টররা ম্যাট্রিক্স ক্লাসে মতলব পছন্দ মত অ্যাক্সেস শৈলী সরবরাহ করতে সহায়তা করতে পারে । একটি উদাহরণ আছে


এটি (ম্যাট্রিক্স উদাহরণ) হ'ল operator()ফাংশন অবজেক্টের বৈশিষ্ট্যগুলির ব্যবহার না করা কিন্তু plain
রেনারডেস্ক

3

যেমন পুনরাবৃত্তি হয়েছে, ফান্ট্যাক্টর এমন ক্লাস যা ফাংশন (ওভারলোড অপারেটর ()) হিসাবে বিবেচনা করা যেতে পারে।

এগুলি পরিস্থিতিতে এমন পরিস্থিতিতে কার্যকর যা আপনার কোনও ক্রিয়ায় বারবার বা বিলম্বিত কলগুলির সাথে কিছু ডেটা সংযুক্ত করতে হবে।

উদাহরণস্বরূপ, ফ্যান্টেক্টরগুলির একটি লিঙ্কযুক্ত তালিকাটি একটি বেসিক লো-ওভারহেড সিঙ্ক্রোনাস কর্টিন সিস্টেম, একটি টাস্ক ডিসপাচারার বা ব্যাঘাতযোগ্য ফাইল পার্সিং প্রয়োগ করতে ব্যবহৃত হতে পারে। উদাহরণ:

/* prints "this is a very simple and poorly used task queue" */
class Functor
{
public:
    std::string output;
    Functor(const std::string& out): output(out){}
    operator()() const
    {
        std::cout << output << " ";
    }
};

int main(int argc, char **argv)
{
    std::list<Functor> taskQueue;
    taskQueue.push_back(Functor("this"));
    taskQueue.push_back(Functor("is a"));
    taskQueue.push_back(Functor("very simple"));
    taskQueue.push_back(Functor("and poorly used"));
    taskQueue.push_back(Functor("task queue"));
    for(std::list<Functor>::iterator it = taskQueue.begin();
        it != taskQueue.end(); ++it)
    {
        *it();
    }
    return 0;
}

/* prints the value stored in "i", then asks you if you want to increment it */
int i;
bool should_increment;
int doSomeWork()
{
    std::cout << "i = " << i << std::endl;
    std::cout << "increment? (enter the number 1 to increment, 0 otherwise" << std::endl;
    std::cin >> should_increment;
    return 2;
}
void doSensitiveWork()
{
     ++i;
     should_increment = false;
}
class BaseCoroutine
{
public:
    BaseCoroutine(int stat): status(stat), waiting(false){}
    void operator()(){ status = perform(); }
    int getStatus() const { return status; }
protected:
    int status;
    bool waiting;
    virtual int perform() = 0;
    bool await_status(BaseCoroutine& other, int stat, int change)
    {
        if(!waiting)
        {
            waiting = true;
        }
        if(other.getStatus() == stat)
        {
            status = change;
            waiting = false;
        }
        return !waiting;
    }
}

class MyCoroutine1: public BaseCoroutine
{
public:
    MyCoroutine1(BaseCoroutine& other): BaseCoroutine(1), partner(other){}
protected:
    BaseCoroutine& partner;
    virtual int perform()
    {
        if(getStatus() == 1)
            return doSomeWork();
        if(getStatus() == 2)
        {
            if(await_status(partner, 1))
                return 1;
            else if(i == 100)
                return 0;
            else
                return 2;
        }
    }
};

class MyCoroutine2: public BaseCoroutine
{
public:
    MyCoroutine2(bool& work_signal): BaseCoroutine(1), ready(work_signal) {}
protected:
    bool& work_signal;
    virtual int perform()
    {
        if(i == 100)
            return 0;
        if(work_signal)
        {
            doSensitiveWork();
            return 2;
        }
        return 1;
    }
};

int main()
{
     std::list<BaseCoroutine* > coroutineList;
     MyCoroutine2 *incrementer = new MyCoroutine2(should_increment);
     MyCoroutine1 *printer = new MyCoroutine1(incrementer);

     while(coroutineList.size())
     {
         for(std::list<BaseCoroutine *>::iterator it = coroutineList.begin();
             it != coroutineList.end(); ++it)
         {
             *it();
             if(*it.getStatus() == 0)
             {
                 coroutineList.erase(it);
             }
         }
     }
     delete printer;
     delete incrementer;
     return 0;
}

অবশ্যই, এই উদাহরণগুলি এগুলি নিজেদের মধ্যে কার্যকর নয়। তারা কেবল দেখায় যে ফান্টেক্টরগুলি কীভাবে কার্যকর হতে পারে, ফান্টরগুলি নিজেরাই খুব মৌলিক এবং জটিল নয় এবং এটি এগুলিকে কম দরকারী করে তোলে, উদাহরণস্বরূপ, বুস্ট কী সরবরাহ করে।


2

প্রকৃত সি ++ ফাংশন বা পদ্ধতির সাথে কিছু জিইউআই বোতাম সংযোগ করতে gtkmm ব্যবহার করা হয় ফ্যাক্টরগুলি।


আপনি যদি অ্যাপ্লিকেশনটিকে মাল্টিথ্রেডেড করার জন্য pthread লাইব্রেরি ব্যবহার করেন তবে ফ্যান্ট্যাক্টররা আপনাকে সহায়তা করতে পারে।
একটি থ্রেড শুরু করতে, তার আর্গুমেন্টগুলির মধ্যে একটি pthread_create(..)হল তার নিজের থ্রেডে কার্যকর করা ফাংশন পয়েন্টার exec
তবে একটি অসুবিধা আছে। এই পয়েন্টার, একটি পদ্ধতি একটি পয়েন্টার হতে পারে না যদি না তা একটি ব্যাপার স্ট্যাটিক পদ্ধতি , বা, যদি না আপনি এটা বর্গ উল্লেখ মত class::method। এবং অন্য একটি জিনিস, আপনার পদ্ধতির ইন্টারফেসটি কেবল এটিই হতে পারে:

void* method(void* something)

সুতরাং আপনি চালাতে পারবেন না (একটি সহজ সুস্পষ্ট উপায়ে), অতিরিক্ত কিছু না করে থ্রেডে আপনার ক্লাসের পদ্ধতিগুলি।

সি ++ তে থ্রেডগুলি মোকাবেলার একটি খুব ভাল উপায় আপনার নিজস্ব Threadবর্গ তৈরি করছে । আপনি যদি MyClassক্লাস থেকে পদ্ধতিগুলি চালনা করতে চান তবে আমি যা করলাম সেগুলি Functorউদ্ভাবিত শ্রেণিতে রূপান্তর কর ।

এছাড়াও, Threadশ্রেণিতে এই পদ্ধতি রয়েছে: static void* startThread(void* arg)
কল করার পক্ষে এই পদ্ধতির একটি পয়েন্টারটি আর্গুমেন্ট হিসাবে ব্যবহৃত হবে pthread_create(..)। আর startThread(..)আর্গের মাধ্যমে যা পাওয়া উচিত তা হ'ল যে void*কোনও Functorউদ্ভূত শ্রেণীর স্তূপের কোনও উদাহরণের জন্য একটি আবদ্ধ রেফারেন্স , যা Functor*মৃত্যুদন্ড কার্যকর করার পরে ফিরে কাস্ট করা হবে , এবং তারপরে এটিকে run()পদ্ধতি বলা হবে ।


2

যোগ করার জন্য, আমি কমান্ড প্যাটার্নটিতে বিদ্যমান উত্তরাধিকার পদ্ধতিতে ফিট করার জন্য ফাংশন অবজেক্ট ব্যবহার করেছি; (কেবলমাত্র যেখানে OO দৃষ্টান্তটির সত্যিকারের OCP এর সৌন্দর্য আমি অনুভব করেছি); এছাড়াও এখানে সম্পর্কিত ফাংশন অ্যাডাপ্টার প্যাটার্ন যুক্ত করুন।

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

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
};

এছাড়াও, কলিংয়ে সহায়তা করার জন্য আমাদের উপরের শ্রেণীর জন্য একটি সহায়ক পদ্ধতি mem_fun3 প্রয়োজন।

template<typename _Ret,typename _Class,typename _arg1,typename _arg2,typename _arg3>
mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3> mem_fun3 ( _Ret (_Class::*_Pm)          (_arg1,_arg2,_arg3) )
{
  return (mem_fun3_t<_Ret,_Class,_arg1,_arg2,_arg3>(_Pm));

}

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

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);
}

এখন আমাদের কমান্ড ক্লাসের সাহায্যে এটি ব্যবহার করতে হবে; নিম্নলিখিত টাইপিডেফ ব্যবহার করুন:

typedef binder3<mem_fun3_t<int,T,int,int,int> ,T* ,int,int,int> F3;
//and change the signature of the ctor
//just to illustrate the usage with a method signature taking more than one parameter
explicit Command(T* pObj,F3* p_method,long timeout,const char* key,
long priority = PRIO_NORMAL ):
m_objptr(pObj),m_timeout(timeout),m_key(key),m_value(priority),method1(0),method0(0),
method(0)
{
    method3 = p_method;
}

আপনি এটি কল কিভাবে এখানে:

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

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

নীচের লিঙ্কে এই নিদর্শনটির সম্পূর্ণ প্রসঙ্গ


2

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

নীচে ওয়াগনার-ফিশার অ্যালগরিদমকে ফান্টিকার হিসাবে প্রয়োগ করার উদাহরণ দেওয়া আছে। কীভাবে কনস্ট্রাক্টরে টেবিলটি বরাদ্দ করা হয়েছে এবং তারপরে পুনরায় পুনরায় ব্যবহার করা হয়েছে operator(), প্রয়োজনীয় আকার পরিবর্তন করে।

#include <string>
#include <vector>
#include <algorithm>

template <typename T>
T min3(const T& a, const T& b, const T& c)
{
   return std::min(std::min(a, b), c);
}

class levenshtein_distance 
{
    mutable std::vector<std::vector<unsigned int> > matrix_;

public:
    explicit levenshtein_distance(size_t initial_size = 8)
        : matrix_(initial_size, std::vector<unsigned int>(initial_size))
    {
    }

    unsigned int operator()(const std::string& s, const std::string& t) const
    {
        const size_t m = s.size();
        const size_t n = t.size();
        // The distance between a string and the empty string is the string's length
        if (m == 0) {
            return n;
        }
        if (n == 0) {
            return m;
        }
        // Size the matrix as necessary
        if (matrix_.size() < m + 1) {
            matrix_.resize(m + 1, matrix_[0]);
        }
        if (matrix_[0].size() < n + 1) {
            for (auto& mat : matrix_) {
                mat.resize(n + 1);
            }
        }
        // The top row and left column are prefixes that can be reached by
        // insertions and deletions alone
        unsigned int i, j;
        for (i = 1;  i <= m; ++i) {
            matrix_[i][0] = i;
        }
        for (j = 1; j <= n; ++j) {
            matrix_[0][j] = j;
        }
        // Fill in the rest of the matrix
        for (j = 1; j <= n; ++j) {
            for (i = 1; i <= m; ++i) {
                unsigned int substitution_cost = s[i - 1] == t[j - 1] ? 0 : 1;
                matrix_[i][j] =
                    min3(matrix_[i - 1][j] + 1,                 // Deletion
                    matrix_[i][j - 1] + 1,                      // Insertion
                    matrix_[i - 1][j - 1] + substitution_cost); // Substitution
            }
        }
        return matrix_[m][n];
    }
};

1

কোনও ফাংশনের মধ্যে স্থানীয় ফাংশন সংজ্ঞায়িত করার জন্য ফান্টাকরও ব্যবহার করা যেতে পারে। পড়ুন প্রশ্ন এবং অন্য

তবে একটি স্থানীয় ফান্টর বাইরে থেকে অটো ভেরিয়েবল অ্যাক্সেস করতে পারে না। ল্যাম্বদা (সি ++ 11) ফাংশনটি আরও ভাল সমাধান।


-10

আমি ফান্ট্যাক্টারের খুব আকর্ষণীয় ব্যবহারটি "আবিষ্কার" করেছি: আমি যখন একটি পদ্ধতির জন্য আমার ভাল নাম না থাকে তখন আমি সেগুলি ব্যবহার করি, কারণ ফ্যান্ট্যাকর নাম ছাড়াই একটি পদ্ধতি ;-)


কেন আপনি কোনও ফান্টরকে "নামবিহীন পদ্ধতি" হিসাবে বর্ণনা করেন?
অ্যান্ডারসন সবুজ

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