2011-10-06 10 views
5

Attualmente sto facendo alcuni esercizi con funzioni basate su modelli. Avevo il compito di scrivere un'implementazione dell'algoritmo di trasformazione. ho fatto come il seguente e funziona:lambda con modelli

template <class in, class out, class T> 
out stransform(in b, in e, out d, T p(const T&)) { 
    while (b != e) 
     *d++ = p(*b++); 
    return d; 
} 

Come per il normale trasformare devo chiamare il predicato con un tipo esplicito come

stransform(begin(vec1), end(vec1), back_inserter(vec2), predi<double>); 

Ora, sono incappato in C++ 11 lambda e voleva chiamare la mia funzione come questa:

stransform(begin(vec1), end(vec1), back_inserter(vec2), [] (double x) ->double {return x * 10;}); 

Con che faccio un errore di compilatore che il tipo cant essere dedotta. Questa è la cosa che non capisco dato che sto definendo il tipo T nel mio lambda in realtà due volte.

Ho controllato anche la funzione di trasformazione originale, con cui sta funzionando. Ho quindi controllato lo implementation di quello ed è ovviamente implementato con una classe template per l'intera funzione. È il modo corretto di implementare predicati con i modelli?

risposta

13

il predicato è di solito un semplice argomento di un template:

template <class in, class out, class UnaryPredicate> 
out stransform(in b, in e, out d, UnaryPredicate p); 

Questo accetterà puntatori a funzione, lambda e oggetti funzione.

+0

Ho pensato così dopo aver letto l'implementazione della trasformazione, che lo rende anche molto più semplice. Mi chiedo ancora perché non lavoro nell'altro caso. – inf

+5

@bamboon Immagino perché un lambda non è una funzione ma un oggetto funzione, in quanto può anche contenere lo stato (è una chiusura e non solo una funzione). –

+1

Si noti che un lambda che non esegue alcuna cattura è convertibile in una funzione ordinaria (puntatore). – spraff

2

T p(const T&) è il tipo di funzione che prende un Tper riferimento. Il tuo lambda prende la sua argomentazione per il valore .

stransform (
    begin (vec1), 
    end (vec1), 
    back_inserter (vec2), 
    [] (const double & x) -> double { 
     return x * 10; 
    }); 

Questo dovrebbe funzionare. Un lambda che non esegue alcuna cattura è convertibile in una funzione ordinaria.

+1

ma perché fare affidamento su una conversione non necessaria al puntatore a funzione, quando si potrebbe ridefinire il funzionamento del funtore con i funtori e con i puntatori di funzione? – jalf

+0

non funziona per me (usando msvc2011), neanche. – inf

+0

@jalf La ridefinizione del functor è una soluzione migliore, sono d'accordo. Se questo problema si presenta con un codice libreria immutabile, la conversione può funzionare. – spraff

2

è ovviamente implementato con una classe modello per l'intera funzione

Leggera da parte per la terminologia corretta: std::transform è una funzione modello, non una funzione. Ancora più importante, in una dichiarazione dello stile

template<class InputIterator, class OutputIterator, class Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

il modello parametri InputIterator, OutputIterator e Functor non sono tenuti a essere tipi di classe. Considerate questo esempio:

// function declaration 
int increment(int); 

int array[] = { 0, 1, 2, 3, 4 }; 
transform(std::begin(array), std::end(array), std::begin(array), increment); 

Poi InputIterator e OutputIterator si deducono di essere int* e Functor è int(*)(int), nessuno dei quali è un tipo di classe - e tanto meno una classe template, ma sto divagando. E infatti, transform potrebbe altrettanto bene essere dichiarato

template<typename InputIterator, typename OutputIterator, typename Functor> 
OutputIterator 
transform(InputIterator begin, InputIterator end, OutputIterator out, Functor f); 

in cui la parola chiave typename è un po 'più chiaro sulla natura dei parametri del modello: sono i tipi, di qualsiasi natura.