Domanda

Continuo a sentire molto parlare di funtori in C++.Qualcuno può darmi una panoramica di cosa sono e in quali casi sarebbero utili?

È stato utile?

Soluzione

Un funtore è praticamente solo una classe che definisce l'operatore (). Che consente di creare oggetti che "sembrano" una funzione:

// 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

Ci sono un paio di cose belle di funtori. Uno è che a differenza di funzioni regolari, che possono contenere Stato. L'esempio sopra crea una funzione che aggiunge 42 a tutto ciò che si dà. Ma che il valore 42 non è codificato, è stato specificato come argomento del costruttore quando abbiamo creato il nostro esempio funtore. Potrei creare un altro vipera, che ha aggiunto 27, semplicemente chiamando il costruttore con un valore diverso. Questo li rende ben personalizzabile.

Per quanto le ultime righe mostrano, spesso si passa funtori come argomenti per altre funzioni come std :: trasformare o gli altri algoritmi della libreria standard. Si potrebbe fare lo stesso con un puntatore a funzione regolare ad eccezione, come ho detto sopra, funtori possono essere "personalizzato" perché contengono stato, rendendoli più flessibili (Se volessi usare un puntatore a funzione, avrei dovuto scrivere una funzione che ha aggiunto esattamente 1 al suo argomento. Il funtore è generale, e aggiunge tutto ciò è stata inizializzata con), e sono anche potenzialmente più efficiente. Nell'esempio precedente, il compilatore sa esattamente quale funzione std::transform dovrebbe chiamare. Si dovrebbe chiamare add_x::operator(). Ciò significa che può inline che chiamata di funzione. E che lo rende altrettanto efficace come se avessi chiamato manualmente la funzione su ciascun valore del vettore.

Se avessi passato un puntatore a funzione, invece, il compilatore non poteva vedere subito quale funzione a cui punta, quindi a meno che non esegue alcuni piuttosto complesse ottimizzazioni globali, essa avrebbe dovuto dereference il puntatore in fase di esecuzione, e poi fare il chiamare.

Altri suggerimenti

piccola aggiunta. È possibile utilizzare boost::function , per creare funtori di funzioni e metodi, come questo:

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"

e si può usare boost :: bind aggiungere stato a questo funtore

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"

e più utile, con boost :: bind e boost :: funzione è possibile creare funtore dal metodo di classe, in realtà questo è un delegato:

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"

È possibile creare elenco o vettore di funtori

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

C'è un problema con tutta questa roba, i messaggi di errore del compilatore non è leggibile:)

Un Functor è un oggetto che agisce come una funzione. Fondamentalmente, una classe che definisce operator().

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

MyFunctor doubler;
int x = doubler(5);

Il vero vantaggio è che un funtore può contenere Stato.

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)
{ ....}

Nome "funtore" è stato tradizionalmente usato in teoria categoria molto tempo prima che C ++ è apparso sulla scena . Questo non ha nulla a che fare con C ++ concetto di funtore. E 'meglio usare nome oggetto Funzione al posto di ciò che chiamiamo "funtore" in C ++. Questo è il modo in altri linguaggi di programmazione chiamano costrutti simili.

Utilizzato al posto di funzione semplice:

Caratteristiche:

  • oggetto Function può avere stato
  • oggetto Function si inserisce in OOP (si comporta come ogni altro oggetto).

Contro:

  • porta più complessità al programma.

Utilizzato al posto del puntatore a funzione:

Caratteristiche:

  • oggetto Function spesso possono essere inline

Contro:

  • oggetto funzione non può essere scambiato con altro tipo di funzione oggetto durante il funzionamento (almeno meno che estende una classe di base, che genera pertanto un overhead)

Utilizzato al posto di funzione virtuale:

Caratteristiche:

  • oggetto Function (non virtuale) non richiede vtable e runtime di dispacciamento, in tal modo è più efficiente nella maggior parte dei casi

Contro:

  • oggetto funzione non può essere scambiato con altro tipo di funzione oggetto durante il funzionamento (almeno meno che estende una classe di base, che genera pertanto un overhead)

Come altri hanno già detto, un funtore è un oggetto che agisce come una funzione, cioè sovraccarica l'operatore chiamata di funzione.

Funtori sono comunemente utilizzati in algoritmi STL. Sono utili perché possono mantenere lo stato prima e tra le chiamate di funzione, come una chiusura in linguaggi funzionali. Ad esempio, è possibile definire un funtore MultiplyBy che moltiplica il suo argomento per un ammontare prestabilito:

class MultiplyBy {
private:
    int factor;

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

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

Poi si potrebbe passare un oggetto transform ad un algoritmo come std :: trasformare:

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

Un altro vantaggio di un funtore nel corso di un puntatore a una funzione è che la chiamata può essere inline in più casi. Se avete passato un puntatore a funzione a <=>, a meno che che chiamata ottenuto inline e il compilatore sa che si passa sempre la stessa funzione ad esso, non può inline la chiamata tramite il puntatore.

Per i neofiti come me tra noi:dopo una piccola ricerca ho capito cosa faceva il codice pubblicato da Jalf.

Un funtore è una classe o un oggetto struct che può essere "chiamato" come una funzione.Ciò è reso possibile sovraccaricando il () operator.IL () operator (non sono sicuro di come si chiami) può accettare un numero qualsiasi di argomenti.Altri operatori ne prendono solo due, ad es.IL + operator può accettare solo due valori (uno su ciascun lato dell'operatore) e restituire il valore per cui lo hai sovraccaricato.Puoi inserire un numero qualsiasi di argomenti all'interno di a () operator che è ciò che gli conferisce la sua flessibilità.

Per creare un funtore devi prima creare la tua classe.Quindi crei un costruttore per la classe con un parametro di tua scelta di tipo e nome.Questo è seguito nella stessa istruzione da un elenco di inizializzatori (che utilizza un singolo operatore due punti, qualcosa a cui ero nuovo) che costruisce gli oggetti membro della classe con il parametro precedentemente dichiarato al costruttore.Poi il () operator è sovraccarico.Infine dichiari gli oggetti privati ​​della classe o della struttura che hai creato.

Il mio codice (ho trovato confusi i nomi delle variabili di 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.
}; 

Se qualcosa di tutto ciò è inaccurato o semplicemente sbagliato, sentiti libero di correggermi!

Un functor è un funzione di ordine superiore che applica una funzione al parametrizzata ( cioè tipi templated). È una generalizzazione della mappa funzione di ordine superiore. Ad esempio, potremmo definire un funtore per std::vector in questo modo:

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

Questa funzione richiede un std::vector<T> e restituisce std::vector<U> quando somministrato una funzione che prende un F T e restituisce un U. Un functor non deve essere definita sui tipi di contenitori, può essere definita per qualsiasi tipo templated pure, compreso 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)));
}

Ecco un semplice esempio che converte il tipo di una 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);

Ci sono due leggi che functors dovrebbero seguire. La prima è la legge identità, che afferma che se il funtore viene data una funzione identità, dovrebbe essere lo stesso che si applica la funzione identità al tipo, cioè fmap(identity, x) dovrebbe essere uguale 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);

La legge successiva è la legge composizione, in cui si afferma che se il funtore viene data una composizione di due funzioni, deve essere la stessa applicazione del functor per la prima funzione e poi ancora per la seconda funzione. Così, fmap(std::bind(f, std::bind(g, _1)), x) dovrebbe essere lo stesso di 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));

Ecco una situazione reale in cui sono stato costretto a utilizzare un funtore per risolvere il mio problema:

Ho un insieme di funzioni (ad esempio, 20 di essi), e sono tutti identici, tranne ogni chiama una diversa funzione specifica in 3 punti specifici.

Questo è incredibile spreco e duplicazione del codice. Normalmente avrei semplicemente passare in un puntatore a funzione, e basta chiamare che nei 3 punti. (Quindi il codice ha bisogno solo di apparire una volta, invece di venti volte.)

Ma poi ho capito, in ogni caso, la funzione specifica richiesto un profilo di parametri completamente diverso! A volte 2 parametri, a volte 5 parametri, ecc.

Un'altra soluzione potrebbe essere quella di avere una classe base, dove la funzione specifica è un metodo override in una classe derivata. Ma voglio veramente a costruire tutto questo eredità, solo così posso passare un puntatore a funzione ????

SOLUZIONE: Quindi quello che ho fatto è stato, ho fatto una classe wrapper (un "Functor"), che è in grado di chiamare una delle funzioni avevo bisogno chiamato. Ho impostato in anticipo (con i relativi parametri, ecc) e poi lo passo in posto di un puntatore a funzione. Ora il codice chiamato può attivare il Functor, senza sapere che cosa sta accadendo al suo interno. Si può anche chiamare più volte (di cui avevo bisogno per chiamare 3 volte).


Questo è tutto - un esempio pratico in cui un funtore si è rivelata la soluzione più ovvia e semplice, che mi ha permesso per ridurre la duplicazione del codice da 20 funzioni per 1

.

A parte utilizzato in richiamata, funtori C ++ possono anche contribuire a fornire un Matlab simpatia stile accesso ad un matrice di classe. C'è un esempio .

Funtori sono utilizzati per collegare gtkmm qualche pulsante GUI per una funzione effettiva C ++ o metodo.


Se si utilizza la libreria pthread per rendere la vostra applicazione multithread, Funtori può aiutare.
Per avviare un filo, uno degli argomenti del pthread_create(..) è il puntatore a funzione da eseguire sul proprio thread.
 Ma c'è un inconveniente. Questo puntatore non può essere un puntatore a un metodo, a meno che non si tratta di un metodo statico , o se non si specificare che è di classe , come class::method. E un'altra cosa, l'interfaccia del tuo metodo non può che essere:

void* method(void* something)

Quindi, non è possibile eseguire (in modo semplice ovvio), i metodi dalla classe in un filo senza fare qualcosa in più.

Un ottimo modo di trattare con fili in C ++, sta creando il proprio Thread classe. Se si voleva correre metodi da MyClass di classe, quello che ho fatto è stato, trasformare quei metodi in Functor classi derivate.

Inoltre, la classe static void* startThread(void* arg) ha questo metodo: startThread(..)
Un puntatore a questo metodo verrà utilizzato come argomento per chiamare void*. E ciò Functor* dovrebbe ricevere in arg è un run() pressofuso riferimento ad un caso in mucchio di classe qualsiasi <=> derivata, che verrà colato ritorna <=> quando eseguito, e poi chiamato è <=> metodo.

Per aggiungere, ho usato oggetti funzione per adattare un metodo patrimonio esistente per il modello di comando; (Inserire solo dove la bellezza della OO paradigma vero OCP ho sentito);  aggiungendo Anche qui il relativo modello di adattatore per la funzione.

Si supponga che il metodo ha la firma:

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

Vedremo come possiamo adattarlo per il modello di comando - per questo, in primo luogo, si deve scrivere un adattatore funzione membro in modo che possa essere definito come un oggetto funzione

.

Nota - questo è brutto, e può essere è possibile utilizzare le aiutanti Boost legano ecc, ma se non si può o non si vuole, questo è un modo

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

Inoltre, abbiamo bisogno di un metodo di supporto mem_fun3 per la classe di cui sopra per aiutare a chiamata.

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

}

Ora, al fine di impegnare i parametri, dobbiamo scrivere una funzione di legante. Quindi, qui va:

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

E, una funzione di supporto per utilizzare la classe 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);
}

Ora, dobbiamo usare questo con la classe di comando; utilizzare il seguente 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;
}

Ecco come si chiamano:

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

Nota: f3 (); chiamerà il metodo task1-> ThreeParameterTask (21,22,23);.

Il contesto pieno di questo modello al seguente collegamento

Come è stato ripetuto, funtori sono classi che possono essere trattati come funzioni (operatore di sovraccarico ()).

Sono più utili per le situazioni in cui è necessario associare alcuni dati con i ripetuti inviti o ritardate a una funzione.

Per esempio, una lista concatenata di funtori potrebbe essere utilizzato per implementare un sistema di base basso overhead sincrono coroutine, un dispatcher compito, o parsing di file interrompibile. Esempi:

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

Naturalmente, questi esempi non sono così utili in se stessi. Essi mostrano solo come funtori possono essere utili, i funtori stessi sono molto semplici e poco flessibile e questo li rende meno utile, per esempio, quello che fornisce spinta.

Un grande vantaggio di funzioni di esecuzione in quanto functors è che possono mantenere e riutilizzare lo stato tra chiamate. Ad esempio, molti algoritmi di programmazione dinamica, come l'algoritmo Wagner-Fischer per il calcolo del Levenshtein distanza tra stringhe, lavoro compilando un grande tavolo di risultati. E 'molto inefficiente per allocare questa tabella ogni volta che la funzione viene chiamata, in modo implementando la funzione come functor e rendendo il tavolo un membro variabile può migliorare notevolmente le prestazioni.

Segue un esempio di implementazione dell'algoritmo Wagner-Fischer come functor. Si noti come la tabella è allocato nel costruttore, e quindi riutilizzato in operator(), con ridimensionamento se necessario.

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

Functor può anche essere utilizzato per simulare definire una funzione locale all'interno di una funzione. Fare riferimento alla domanda e un'altra .

Ma un funtore locale non può accedere alle variabili auto esterni. La funzione lambda (C ++ 11) è una soluzione migliore.

Ho "scoperto" un uso molto interessante di funtori: li uso quando non ho un buon nome per un metodo, come un funtore è un metodo senza nome; -)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top