2013-03-17 15 views
10

Sto cercando di scrivere una funzione generica piega utilizzando le nuove funzioni anonime disponibili in C++ 11, qui è quello che ho:Funzioni di ordine superiore in C++ 11

template<typename T> 
T foldl(std::function<T(T,T)> f, T initial, std::vector<T> items) { 
    T accum = initial; 
    for(typename std::vector<T>::iterator it = items.begin(); it != items.end(); ++it) { 
     accum = f(accum, (*it)); 
    } 
    return accum; 
} 

Il seguente tentativo per usarlo:

std::vector<int> arr; 
arr.assign(8, 2); 
foldl([] (int x, int y) -> int { return x * y; }, 1, arr); 

causa un errore:

main.cpp:44:61: error: no matching function for call to 'foldl(main(int, char**)::<lambda(int, int)>, int, std::vector<int>&)' 
main.cpp:44:61: note: candidate is: 
main.cpp:20:3: note: template<class T> T foldl(std::function<T(T, T)>, T, std::vector<T>) 
main.cpp:20:3: note: template argument deduction/substitution failed: 
main.cpp:44:61: note: 'main(int, char**)::<lambda(int, int)>' is not derived from 'std::function<T(T, T)>' 

mi sembra che l'uso di std::function non è il giusto wa y per definire il tipo di f. Come posso correggere questo?

+0

C'è qualcosa di sbagliato [con 'std :: accumulate'] (http://en.cppreference.com/w/cpp/algorithm/accumulate)? –

+1

Sto solo giocando in C++ e volevo scrivere il mio. – defectivehalt

risposta

14

Il tuo codice non è molto generico. Non è necessario richiedere un function, vector o qualcosa del genere. E in generale, in C++, le funzioni andrebbero alla fine della lista degli argomenti (particolarmente importante per lambda, dato che possono essere grandi).

Quindi sarebbe meglio (es: più standard) di scrivere questo come questo:

template<typename Range, typename Accum> 
typename Range::value_type foldl(const Range &items, const typename Range::value_type &initial, Accum f) 
{ 
    typename Range::value_type accum = initial; 
    for(const auto &val : items) { 
     accum = f(accum, val); 
    } 

    return accum; 
} 

o si può solo use std::accumulate che fa la stessa identica cosa.

+2

Interessante. Inoltre, credo che manchi un 'typename' quando dichiari' accum'. – defectivehalt

+0

@KavonFarvardin: corretto. Grazie! –

+0

Puoi spiegare perché le funzioni dovrebbero essere passate come ultimo argomento? E i lambda sono grandi? Che cosa? Non è solo un riferimento di funzione, come qualsiasi altra funzione passata così? – Praxeolitic

4

Non sono sicuro del motivo per cui questo modello non funziona, ma passare a utilizzare un parametro di modello per la funzione anziché std::function<> sembra funzionare in modo straordinario.

template<typename T, typename F> 
T foldl(F f, T initial, std::vector<T> items) { 
2

Se avete semplicemente convertirlo in un std::function prima, e quindi utilizzare tale, funzionerà:

std::vector<int> arr; 
arr.assign(8, 2); 
std::function<int(int,int)> f = [] (int x, int y) -> int { return x * y; }; 
foldl(f, 1, arr); 

Il problema è che lambda è un tipo diverso rispetto std::function. Ogni lambda è un tipo separato. Sebbene un lambda (e tutti gli altri oggetti funzione) sia convertibile in un std::function con il parametro di tipo appropriato, il compilatore non ha idea di quale argomento modello per T possa renderlo convertibile. (Sappiamo che T = int funzionerebbe, ma non c'è un modo generale per capirlo.) Quindi non può compilarlo.

+0

Quindi, la maggior parte dei compilatori non ha la capacità di dedurre che il tipo 'T' deve essere' int'? Perché non vedo davvero perché altrimenti ci sarebbe un problema. – defectivehalt

+0

@ KavonFarvardin: Sì. Credo che non sia possibile farlo secondo lo standard. Di solito, quando converti un tipo in una 'std :: function ', inserisce il tuo dato tipo nel costruttore per vedere se funziona ", per tentativi ed errori. Sappiamo che il segreto di ciò che "funziona" è che il tipo del metodo 'operator()' sull'oggetto corrisponde al parametro di 'std :: function', ma ciò non è possibile da capire guardando il tipo e credo non sia possibile esprimerlo nella lingua.Per quello che ne sa, potrebbero esserci molti parametri di tipo che "funzionano". – newacct

Problemi correlati