2013-08-21 10 views
6

Con l'avvento di C++ 11, abbiamo unordered_map.cbegin/cend per restituire specificamente i valori di const_iterator. quindi il tipo di "esso" dedotto nell'espressione "auto it = unordered_map.cbegin()" è const_iterator.Tipo ridotto di "auto it = unordered_map.find (chiave)"?

Tuttavia, quando si tratta della funzione unordered_map.find (chiave), penso che possa mancare una controparte "cfind()", che restituisce un const_iterator in modo specifico.

Alcuni dicono che possiamo usare "const auto it = unordered_map.find (chiave)" per ottenere un "const iterator", ma ho il forte sospetto che "const iterator" sia lo stesso "const_iterator", dove " const iterator "limita la possibilità di modificare l'iteratore stesso, mentre" const_iterator "limita la possibilità di modificare il contenuto a cui si riferisce l'iteratore.

Quindi, in realtà, se vogliamo approfittare di tipo detrazione "auto" completamente (con la conoscenza delle confusioni o le variazioni di "auto" tipo deduzione - Auto, Auto &, auto const &, etc.) , come posso avere unordered_map.find (chiave) per restituire un "const_iterator" senza che io debba specificare esplicitamente "const_iterator" - dopo tutto è il caso d'uso migliore per l'auto!

Di seguito è riportato un codice semplice esempio che illustra il comportamento del compilatore:

#include "stdafx.h" 
#include <unordered_map> 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    typedef std::unordered_map<int, int> umiit; 
    umiit umii; 

    auto it0 = umii.find(0); 
    it0->second = 42; 
    const auto it1 = umii.find(0); 
    it1->second = 42; 
    umiit::const_iterator it2 = umii.find(0); 
    it2->second = 42; // expected compiler error: assigning to const 

    return 0; 
} 
+0

Qual è la domanda? –

+0

La domanda è nel quarto paragrafo: ** come posso avere unordered_map.find (chiave) per restituire un "const_iterator" senza che io debba specificare esplicitamente "const_iterator"?** – dfan

risposta

2

Sono non è a conoscenza di un luogo che prende uno const_iterator in cui non si può semplicemente passare un iterator, quindi questa mancanza potrebbe non interferire molto con la scrittura del codice giorno per giorno. Tuttavia, preferisco usare const_iterator s (e const in generale) ovunque non sia necessario effettuare la mutazione, nell'interesse della comunicazione generale, quindi penso che aggiungere uno cfind() potrebbe essere un'utile aggiunta alla futura libreria standard.

Penso che questo codice potrebbe funzionare come una semplice soluzione per quello che stai cercando di raggiungere, però:

template<typename T> 
auto use_as_const(T const &t) -> T const & { 
    return t; 
} 

Questa è una semplice funzione di casting involucro, simile nello stile a move() e forward<T>(), per fornire (e documentare) un vincolo sui singoli usi dell'oggetto. È quindi possibile utilizzare in questo modo:

auto it1 = use_as_const(umii).find(0); 

Questo potrebbe essere utilizzato anche invece di appoggiarsi su cbegin() e cend(). Oppure, potrebbe essere utilizzato nella gamma-based per cicli:

for (auto &element : use_as_const(some_vector_of_string)) { 
    cout << element; 
    // element = ""; // This line shouldn't compile. 
} 

Nell'esempio ciclo precedente, anche se avrei in genere preferiscono auto const &element : ..., credo che sarebbe stato inutile e element sarebbe ancora dedotto di essere un riferimento const .

+1

Hai ragione che non ho incontrato problemi nella codifica quotidiana, ma per coerenza e correttezza generale della comunicazione (e potrei essere eccessivamente perfezionata nello scrivere il codice di stile C++ 11/14), cfind sarebbe una grande caratteristica. Sono assolutamente d'accordo che il wrapper use_as_const fa il lavoro, * ma * la funzione è davvero più sensata se è nello standard piuttosto che aggiungere il boilerplate dall'utente (spero che abbia senso). :) – Dejavu

+1

Tuttavia, nell'intervallo basato per caso, use_as_const ha più senso semantico rispetto a "trova". – Dejavu

1

E 'un po' di carenza; abbiamo cbegin e cend ma non corrispondente cfind, ecc

Io suggerirei utilizzando una funzione di utilità per ottenere un riferimento const all'oggetto, come per la risposta a forcing use of cbegin()/cend() in range-based for:

template<typename T> constexpr const T &as_const(T &t) { return t; } 

auto it1 = as_const(umii).find(0); 
it1->second = 42; // fails 
+1

Dovrebbe essere 'const T & as_const (const T & t)', quindi può essere applicato a qualcosa che è già const senza segnalare un errore. –

+0

@ChrisDodd in questo caso 'T' viene dedotto a' const U', quindi non ci sono errori. – ecatmur

Problemi correlati