2015-03-15 4 views
6

Die std::back_insert_iteratorvalue_type gleich void hat, aber es hat auch ein Mitglied protectedcontainer die einen Zeiger auf den Basiswert Container hält. Ich versuche, eine Züge Klasse zu schreiben, den Behälter des value_type, entlang dieser Linien zu extrahieren:Traits Klasse zu extrahieren Containers value_type aus einem back_insert_iterator

#include <iterator> 
#include <type_traits> 
#include <vector> 

template<class OutputIt> 
struct outit_vt 
: 
    OutputIt 
{ 
    using self_type = outit_vt<OutputIt>; 
    using value_type = typename std::remove_pointer_t<decltype(std::declval<self_type>().container)>::value_type; 
}; 

int main() 
{ 
    std::vector<int> v; 
    auto it = std::back_inserter(v); 
    static_assert(std::is_same<outit_vt<decltype(it)>::value_type, int>::value, ""); 
} 

Live Example

jedoch diese (mehr oder weniger expectedly) läuft in unvollständigen Typ Fehler. Gibt es das überhaupt, um die des Containers zu extrahieren?

+0

Warum verwenden Sie keinen verschachtelten Typ, der vom Iterator abgeleitet ist? [Live Beispiel] (http://coliru.stacked-crooked.com/a/3547c063ddfb1ddb) – dyp

+0

@dyp Ich war daft, 'back_insert_iterator' hat eine verschachtelte Typedef' container_type 'sogar – TemplateRex

+0

Siehe kürzlich Live-Beispiel hinzugefügt. - oooh das ist ein öffentliches Mitglied. Ich sehe – dyp

Antwort

6

Die Antwort von @Rapptz ist richtig, aber für generischen Code (dh, wenn es nicht a priori klar, ob man es mit a rohe T* oder back_insert_iterator oder einer der anderen Ausgabe-Iteratoren der Standard-Bibliothek), ist ein systematischer Ansatz notwendig.

Zu diesem Zweck unter einer Definition einer Klassenvorlage output_iterator_traits in einem benutzerdefinierten namespace xstd.

#include <iterator>    // iterator, iterator_traits, input_iterator_tag, output_iterator_tag, random_access_iterator_tag 
           // back_insert_iterator, front_insert_iterator, insert_iterator, ostream_iterator, ostreambuf_iterator 
#include <memory>    // raw_storage_iterator 

namespace xstd { 

template<class T> 
struct output_iterator_traits 
: 
     std::iterator_traits<T> 
{}; 

template< class OutputIt, class T> 
struct output_iterator_traits<std::raw_storage_iterator<OutputIt, T>> 
: 
     std::iterator<std::output_iterator_tag, T> 
{}; 

template<class Container> 
struct output_iterator_traits<std::back_insert_iterator<Container>> 
: 
     std::iterator<std::output_iterator_tag, typename Container::value_type> 
{}; 

template<class Container> 
struct output_iterator_traits<std::front_insert_iterator<Container>> 
: 
     std::iterator<std::output_iterator_tag, typename Container::value_type> 
{}; 

template<class Container> 
struct output_iterator_traits<std::insert_iterator<Container>> 
: 
     std::iterator<std::output_iterator_tag, typename Container::value_type> 
{}; 

template <class T, class charT = char, class traits = std::char_traits<charT>> 
struct output_iterator_traits<std::ostream_iterator<T, charT, traits>> 
: 
     std::iterator<std::output_iterator_tag, T> 
{}; 

template <class charT, class traits = std::char_traits<charT>> 
struct output_iterator_traits<std::ostreambuf_iterator<charT, traits>> 
: 
     std::iterator<std::output_iterator_tag, charT> 
{}; 

} // namespace xstd 

Die unspezialisiert Version erbt einfach von std::iterator_traits<T>, aber für die 6 Ausgabe Iteratoren definiert in den <iterator> und <memory> Header, erben die Spezialisierungen von std::iterator<std::output_iterator_tag, V> wo V der Typ als Argument des Iterators operator=(const V&) erscheint, ist.

für den Einsatz Iteratoren entspricht dies typename Container::value_type, für rohe Speicher Iteratoren T und für ostream und ostreambuf Iteratoren T und charT, respectively.

Ein generischer Algorithmus des Formulars

template<class InputIt, class OutputIt> 
auto my_fancy_algorithm(InputIt first, InputIt last, OutputIt dest) 
{ 
    using T = typename xstd::output_iterator_traits<OutputIt>::value_type; 
    for (; first != last; ++first) { 
     // ... construct arguments from *first 
     *dest++ = T{ /* arguments */ }; 
    } 
} 

dann in transparenter Weise mit beiden arbeiten rohen Zeiger und die Ausgabe Iteratoren Standard-Bibliothek.

2

Sie nur container_type verwenden könnten, dass es hat:

#include <iterator> 
#include <type_traits> 
#include <vector> 

template<typename T> 
struct outit_v { 
    using container_type = typename T::container_type; 
    using value_type = typename container_type::value_type; 
}; 

int main() 
{ 
    std::vector<int> v; 
    auto it = std::back_inserter(v); 
    static_assert(std::is_same<outit_v<decltype(it)>::value_type, int>::value, ""); 
} 

Live Example

Verwandte Themen