2013-07-19 14 views
23

Visual Studio 2013 Preview supporta una funzione C++ 14 chiamata (in base alla pagina this) "Operatori operatore trasparente". Non sono chiaro su cosa significhi. La proposta C++ 14 più vicina che ho trovato è questa, ma non sono sicuro se sia la stessa cosa: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421Operatori operatori trasparenti

Sto cercando una spiegazione più chiara di cosa sia, perché è un miglioramento, e forse un frammento che ne dimostra l'uso.

+0

Se è lo stesso, consente di sostituire 'bool less :: operator() (int const e lhs, int const & rhs) const {return lhs :: operator() (LHS && lhs, RHS && rhs) const-> decltype (std :: forward (lhs) (rhs)) {return std :: forward (lhs) (rhs); } ', una perfetta chiamata" trasparente "di inoltro a' <'. – Yakk

+4

N3421 è la stessa cosa: è stato votato in C++ 14 senza modifiche in quella riunione, ed è quello che ho implementato nel 2013 Anteprima. Ho pensato che la sezione II, "Motivation And Scope", spiegasse chiaramente il problema e la soluzione, e ho pensato che l'esempio nella sezione VIII "Implementazione" ne dimostrasse l'uso. Di cosa sei confuso? –

+0

La pagina "Novità per Visual C++" non menziona la proposta N3421, quindi ho pensato di chiedere qui. Sono chiaro su di esso ora. Grazie per averlo aggiunto. – GravityWell

risposta

22

La proposta di operatori funzionali trasparenti è lì come un modo per avere funtori generalizzati che si trovano in <functional>. Personalmente ritengo che la proposta stessa abbia un ottimo esempio che aiuterebbe a illustrarne la necessità. Comunque andrò avanti e cercherò di spiegarlo.

Supponiamo di avere una funzione, una funzione mente molto di base si:

template<typename T, typename U> 
auto less_than(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)) { 
    return std::forward<T>(t) < std::forward<U>(u); 
} 

Tuttavia si desidera utilizzare questa funzione generalizzata nell'intestazione <algorithm>. Hai due opzioni, per renderlo un funtore struct:

struct MyLessThanFunctor { 
    template<typename T, typename U> 
    auto operator()(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)){ 
     return std::forward<T>(t) < std::forward<U>(u); 
    } 
}; 

O in C++ 14, per fare una lambda polimorfico:

[](auto&& t, auto&& u) -> decltype(auto) { 
    return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u); 
} 

Entrambi sono molto verboso quando viene utilizzato in un algoritmo in questo modo :

int main() { 
    std::vector<int> v = {112,12,1281271,1919101,29181,412,1 }; 
    std::sort(std::begin(v), std::end(v), MyLessThanFunctor()); // one 
    std::sort(std::begin(v), std::end(v), [](auto&& t, auto&& u) -> decltype(auto) { 
     return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u); 
    }); 
} 

questa proposta mira a rendere più compatto e generalizzata facendo questo invece:

std::sort(std::begin(v), std::end(v), std::less<>()); 

Ciò consente un inoltro perfetto e risolve i problemi con il troncamento oi problemi derivanti dalla modifica del contenitore ma non il tipo sottostante nominato dal contenitore come indicato dalla carta.

Supponiamo di avere un funtore non generalizzata:

struct Functor { 
    bool operator()(uint32_t a, uint32_t b) { 
     return a < b; 
    } 
}; 

e si utilizza con il vostro std::vector<uint32_t> e funziona tutto bene, ma dimenticare il tuo functor non essere generalizzata e utilizzarlo con il vostro std::vector<uint64_t>. Riesci a vedere il problema che è sorto? Gli elementi verranno troncati prima di essere confrontati, il che probabilmente non è ciò che l'utente desiderava. I funtori generalizzati risolvono questo problema prima che si presentino.

+2

Puoi usare 'std :: less' et al. anche senza questi funtori trasparenti implementati, ma è molto più spiacevole.'std :: sort (std :: begin (v), std :: end (v), std :: less :: type>());' – Praetorian

+9

Pretorio, considera l'eterogeneo lower_bound() di C++ 11, dove l'intervallo e il valore desiderato possono avere tipi diversi. C++ 98's less accetta (const T &, const T &), quindi non importa quale sia la tua T, non puoi eseguire un confronto eterogeneo. Ciò vale anche per casi semplici come std :: string e const char *. –

+0

L'equivalente lambda è '[] (auto && t, auto && u) -> decltype (auto) {return std :: forward (t) (u); } ', purtroppo –