2011-07-04 11 views
22

I funtori STL sono implementate in questo modo:Perché i funtori STL sono a loro volta modelli e non la loro funzione chiama operatore?

template<class T> 
struct less{ 
    bool operator()(T const& lhs, T const& rhs){ 
    return lhs < rhs; 
    } 
}; 

questo ci fa ricordiamo il (possibilmente lungo) TIPO ogni volta creiamo un tale funtore. Perché non sono implementati come mostrato di seguito? Qualche motivo?

struct less{ 
    template<class T> 
    bool operator()(T const& lhs, T const& rhs){ 
    return lhs < rhs; 
    } 
}; 

Ciò li renderebbe utilizzabili senza alcun riferimento a tipi (possibilmente lunghi).

+0

a partire da C++ 14, è possibile utilizzare [comparatori trasparenti] (http: // stackoverflow.com/q/20317413/819272) che fornisce 'template std :: less ' con 'std :: less ' contenente l'operatore di testo' '<' (e similmente per gli altri functor). – TemplateRex

risposta

23

Inoltre renderebbe impossibile la loro specializzazione per i tipi definiti dall'utente.

Si suppone che siano un punto di personalizzazione.


In sintesi delle discussioni nei commenti:

Anche se è tecnicamente possibile fare come suggerisce Xeo, il linguaggio standard non lo consente.

È molto difficile scrivere un modello di classe lavorativa se gli utenti sono autorizzati a specializzare le singole funzioni del modello. In alcuni casi potrebbe essere comunque una buona idea specializzare l'intera classe per un tipo definito dall'utente.

Pertanto i C++ 98 scrive normali (17.4.3.1):

E non è definito per un programma C++ per aggiungere le dichiarazioni o definizioni di namespace std o spazi dei nomi all'interno di namespace std se non diversamente specificato. Un programma può aggiungere specializzazioni di modelli per qualsiasi modello di libreria standard allo std di namespace.

Poiché non è "specificato altrimenti" che il codice di Xeo è consentito, dobbiamo capire che non lo è. Forse non del tutto ovvio! O che "specializzazioni modello" si applicano solo alle classi.

Il nuovo standard C++ 11 ha avuto questa parte espansa, e scrive la segnalazione dettagliatamente (17.6.4.2):

Il comportamento di un programma C++ è indefinito se si aggiunge dichiarazioni o definizioni nello spazio dei nomi std o in uno spazio dei nomi all'interno dello std del namespace, se non diversamente specificato. Un programma può aggiungere una specializzazione modello per qualsiasi modello di libreria standard allo std dei nomi solo se la dichiarazione dipende da un tipo definito dall'utente e la specializzazione soddisfa i requisiti di libreria standard per il modello originale e non è esplicitamente vietata .

Il comportamento di un programma C++ è indefinito se si dichiara

- una specializzazione esplicita di qualsiasi funzione di membro di un modello di classe libreria standard, o
- una specializzazione esplicita di qualsiasi modello di funzione membro di una libreria standard modello di classe o classe o
- una specializzazione esplicita o parziale di qualsiasi modello di classe membro di una classe di libreria standard o di un modello di classe.

Un programma può esplicitamente creare un'istanza di un modello definito nella libreria standard solo se la dichiarazione dipende dal nome di un tipo definito dall'utente e l'istanza soddisfa i requisiti di libreria standard per il modello originale.

+0

Beh .. che ne dici di crearne uno tuo? Devi comunque creare una "nuova" struttura. – Xeo

+0

Nel caso in cui ciò che Bo ha detto sia difficile da capire, potresti voler definire il modello <> bool less :: operator() (...) {...} – fulmicoton

+0

@poule: 'modello <> bool std :: meno :: operatore() '? O mi sta sfuggendo qualcosa? – Xeo

5

Forse:

std::multiset<long, std::less<int> > moduloset; 

cosa strana da fare, ma il punto è che std::less<int>, std::less<long>, std::less<unsigned int> implementare diverse funzioni matematiche che producono risultati diversi quando viene passato (il risultato della conversione) certe espressioni argomenti. Vari algoritmi e altri componenti delle librerie standard funzionano specificando un funtore, quindi ha senso per me che ci sono diversi funtori per rappresentare quelle diverse funzioni matematiche, non solo diversi sovraccarichi di operator() su un unico functor.

Inoltre, un funtore con un modello operator() non può essere un predicato binario adattabile, poiché non ha tipi di argomenti (un argomento può avere qualsiasi tipo). Quindi, se sono stati definiti std::less come suggerisci, non è possibile partecipare agli elementi in <functional>.

Anche su una nota altamente speculativa - std::less è stato progettato probabilmente prima che il supporto per le funzioni membro del modello fosse del tutto diffuso, dal momento che ci sono varie note nella documentazione SGI STL che dicono "se l'implementazione non supporta i modelli membri" allora questo non è disponibile ". Per una componente così semplice, credo che sarebbe un incentivo a fare qualcosa che funzioni oggi. Una volta esistente, la standardizzazione potrebbe essere stata sostituita da in favore di qualcos'altro, ma valeva la pena interrompere il codice esistente? Se era un grosso problema, allora tu o lo standard potreste introdurre un functor flexible_less mentre descrivete.

Infine, perché

template<class T> 
bool operator()(T const& lhs, T const& rhs){ 
    return lhs < rhs; 
} 

anziché

template<class T, class U> 
bool operator()(T const& lhs, U const& rhs){ 
    return lhs < rhs; 
} 

Per i tipi definiti dall'utente, i due non potrebbero essere lo stesso. Sì, questa è una domanda ingiusta, dal momento che non so perché non ci sia una versione a due template argomento di std::less ;-)

+0

"dal momento che non so perché non ci sia una versione a due template argomento di std :: less" - Crea una nuova domanda! : P – Xeo

Problemi correlati