c++ সি++ ফ্যাক্টর এবং তাদের ব্যবহার কি?




সি++ বই (12)

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


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

সাধারণ ফাংশন পরিবর্তে ব্যবহার করা হয়:

বৈশিষ্ট্য:

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

কনস:

  • প্রোগ্রাম আরো জটিলতা এনেছে।

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

বৈশিষ্ট্য:

  • ফাংশন বস্তু প্রায়ই ইনলাইন করা হতে পারে

কনস:

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

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

বৈশিষ্ট্য:

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

কনস:

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

একটি ফাংশন একটি বস্তু যা একটি ফাংশন মত কাজ করে। মূলত, একটি শ্রেণী যা operator() সংজ্ঞায়িত করে 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)
{ ....}

কলব্যাক ব্যবহার ছাড়া, সি ++ ফাংশ্টরা একটি ম্যাট্রিক্স ক্লাস অ্যাক্সেস স্টাইল ম্যাট্রিক্স ক্লাসে সরবরাহ করতে সহায়তা করতে পারে। একটি example


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

ফাংশ্টগুলি সাধারণত STL অ্যালগরিদম ব্যবহার করা হয়। তারা কার্যকরী কারণ তারা ফাংশন কলগুলির আগে এবং এর মধ্যে রাষ্ট্রকে ধরে রাখতে পারে, যেমন ক্রিয়ামূলক ভাষাগুলিতে বন্ধ। উদাহরণস্বরূপ, আপনি একটি 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 করার জন্য একটি ফাংশন পয়েন্টার পাস করেন, তবে সেই কলটি ইনলাইন না হওয়া পর্যন্ত এবং কম্পাইলারটি জানেন যে আপনি সর্বদা একই ফাংশনটি পাস করেন, এটি পয়েন্টারের মাধ্যমে কলটিতে ইনলাইন করতে পারে না।


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

// this is a functor
struct add_x {
  add_x(int x) : x(x) {}
  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

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

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

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


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

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

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

আমার কোড (আমি jalf এর পরিবর্তনশীল নাম বিভ্রান্তিকর খুঁজে পাওয়া যায় নি)

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

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


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

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


লিটল ছাড়াও। ফাংশন এবং পদ্ধতিগুলি থেকে ফাংশ্টগুলি তৈরি করতে আপনি 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"

এবং আপনি এই functor রাষ্ট্র যোগ করার জন্য boost :: bind ব্যবহার করতে পারেন

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"

এবং সর্বাধিক দরকারী, boost :: bind এবং boost :: ফাংশন দিয়ে আপনি ক্লাস মেথড থেকে ফন্টটর তৈরি করতে পারেন, আসলে এটি একটি প্রতিনিধি:

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

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


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


যোগ করার জন্য, আমি কমান্ড প্যাটার্নের বিদ্যমান লিগ্যাসি পদ্ধতিতে মাপসই করার জন্য ফাংশন অবজেক্টগুলি ব্যবহার করেছি; (শুধুমাত্র স্থান যেখানে 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;
};

এবং, একটি সহায়ক ফাংশন binder3 ক্লাস ব্যবহার করতে - bind3:

//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 ব্যবহার করুন:

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) কল করবে;

নিম্নলিখিত link এ এই প্যাটার্ন পূর্ণ প্রেক্ষাপটে


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

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

void* method(void* something)

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

C ++ তে থ্রেডগুলির সাথে ডিল করার খুব ভাল উপায়, আপনার নিজস্ব Thread বর্গ তৈরি করছে। যদি আপনি MyClass ক্লাস থেকে পদ্ধতি চালাতে চান তবে আমি যা করেছি তা MyClass সেই পদ্ধতিগুলিকে রূপান্তর করুন।

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


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

নীচে একটি ফ্যান্টর হিসাবে ওয়াগনার-ফিশার আলগোরিদিম বাস্তবায়ন করার একটি উদাহরণ। নোটটি কীভাবে কনস্ট্রাক্টারে বরাদ্দ করা হয় তা লক্ষ্য করুন এবং তারপরে প্রয়োজনীয় হিসাবে পুনরায় আকার দিয়ে 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];
    }
};




function-call-operator