2013-10-11 12 views
9

L'intestazione <algorithm> fornisce std::equal_range(), così come alcuni contenitori che lo hanno come funzione membro. Ciò che mi infastidisce di questa funzione è che restituisce una coppia di iteratori, rendendola noiosa da iterare dall'inizio iteratore alla fine iteratore. Mi piacerebbe essere in grado di utilizzare std::begin() e std::end() in modo da poter utilizzare il ciclo for-based basato su intervallo C++ 11.Posso specializzare std :: begin e std :: end per il valore restituito di equal_range()?

Ora, ho sentito informazioni contraddittorie per quanto riguarda specializzata std::begin() e std::end() - Mi è stato detto che l'aggiunta di qualsiasi cosa per i risultati std namespace in un comportamento indefinito, mentre ho anche stato detto che è possibile fornire le proprie specializzazioni di std::begin() e std::end().

Questo è quello che sto facendo in questo momento:

namespace std 
{ 
    template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category> 
    Iter begin(pair<Iter, Iter> const &p) 
    { 
     return p.first; 
    } 
    template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category> 
    Iter end(pair<Iter, Iter> const &p) 
    { 
     return p.second; 
    } 
} 

E questo funziona: http://ideone.com/wHVfkh

Ma mi chiedo, quali sono i lati negativi di fare questo? C'è un modo migliore per farlo?

risposta

7

17.6.4.2.1/1 Il comportamento di un programma C++ è indefinito se si aggiunge dichiarazioni o definizioni per namespace std o per uno spazio dei nomi all'interno dello spazio dei nomi std se non diversamente specificato. Un programma può aggiungere una specializzazione di modello per qualsiasi modello di libreria standard allo spazio nomi std 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.

Quindi sì, credo che, tecnicamente, il codice mostri un comportamento indefinito. Forse puoi scrivere una semplice classe che prende un paio di iteratori nel suo costruttore e implementa i metodi begin() e end(). Quindi puoi scrivere qualcosa come

for (const auto& elem: as_range(equal_range(...))) {} 
+0

Esattamente quanto 'schizzinoso' è la parte su cui è consentito se sono coinvolti tipi definiti dall'utente? La coppia contiene iteratori che iterano su un contenitore di unique_ptrs al mio tipo definito dall'utente. –

+0

Le tue definizioni, come scritte, non menzionano alcun tipo definito dall'utente. Questi modelli potrebbero essere istanziati con tipi definiti dall'utente, ma questo è irrilevante. –

+1

In ogni caso, il "escape dipende dai tipi definiti dall'utente" si applica solo alle specializzazioni del modello. I vostri non sono: sono modelli di funzioni primarie, che capita di sovraccaricare altri modelli di funzioni con lo stesso nome. –

Problemi correlati