2015-02-15 17 views
7

Sto creando una sorta di contenitore e vorrei simulare l'interfaccia di uno std::vector. Tuttavia, sto avendo difficoltà a capire come funziona the constructor overload (4). Il problema è che normalmente è in conflitto con il sovraccarico (2).std :: costruttore vettoriale che accetta una coppia di iteratori

// (2) 
vector(size_type count, const T& value, const Allocator& alloc = Allocator()); 
// (4) 
template<class InputIt> 
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator()); 

Secondo cppreference, fino C++ 11:

questo costruttore ha lo stesso effetto di sovraccarico (2) se InputIt è un tipo intero.

ho capito come è stato fatto (tag invio o il modello di specializzazione, suppongo), ma non ho idea di come il nuovo comportamento è realizzato in C++ 11:

Questo sovraccarico partecipa solo in risoluzione di sovraccarico se InputIt soddisfa InputIterator, per evitare ambiguità con il sovraccarico (2).

È una specie di trucco SFINAE? Non capisco come SFINAE potrebbe funzionare qui. E, dal momento che i concetti o non sono una cosa in C++ 11 (né C++ 14), non ho idea di come potrei farlo per il mio contenitore.

Quindi la mia domanda: come è fatto nella libreria standard (o almeno una supposizione), e come posso farlo relativamente facilmente per il mio contenitore?

+1

Commento pedante: non esiste * l'implementazione della libreria standard. implementazione del vettore di libC++ [usa SFINAE tramite 'enable_if'] (https://github.com/llvm-mirror/libcxx/blob/master/include/vector#L532). libstdC++ [usa un'implementazione simile] (https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01523_source.html#l00401), ma lascia il controllo di costruibilità. – dyp

+0

@dyp Sì, so che non esiste un'implementazione unica, ma non sapevo come formularlo (è per questo che ho aggiunto "o almeno un'ipotesi"). Grazie per i link, è interessante. – Nelfeal

risposta

6

Il modo in cui è formulato attualmente nello standard è piuttosto interessante. [Sequence.reqmts]/p15:

Il grado di un'implementazione determina che un tipo non può essere un iteratore di input è specificato, eccetto che come minimo integrali tipi non sono ammissibili come iteratori di input.

In altre parole, è sufficiente che le implementazioni testino solo i tipi interi, ma possono fare di più se lo desiderano.

Con SFINAE-friendly std::iterator_traits (votato nel documento di lavoro C++ 17 come un problema LWG, ma probabilmente forniti dalla maggior parte delle implementazioni tutti lungo comunque), per esempio, si potrebbe testare il std::iterator_traits<InputIterator>::iterator_category è valido e indica un tipo derivato da std::input_iterator_tag con qualcosa di simile

template<class InputIt, std::enable_if_t<std::is_base_of<std::input_iterator_tag, 
          typename std::iterator_traits<InputIterator>::iterator_category>::value, int> = 0> 
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator()); 

si noti che questo è solo un proof-of-concept. Le implementazioni reali nelle librerie standard sarebbero probabilmente 1) più complesse (ad esempio, potrebbe ottimizzare in base alla categoria iteratore - per gli iteratori in avanti o meglio, può allocare la memoria per tutti gli elementi in una volta sola) e 2) anche più brutti di questa e riempito con caratteri di sottolineatura per evitare conflitti di nome.

Problemi correlati