2015-03-15 13 views
6

std::back_insert_iterator ma value_type równa void, ale ma też protected członek container, która posiada wskaźnik do leżącej Container. Próbuję napisać klasę wyodrębnić cechy kontenera value_type, wzdłuż tych linii:Cechy klasy wyodrębnić VALUE_TYPE kontenera z 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

Jednak to (mniej lub bardziej expectedly) prowadzi do niepełnych błędów typu. Czy jest tu i tak, aby uzyskać ekwipunek kontenera value_type?

+0

Dlaczego nie używasz typu zagnieżdżonego pochodzącego z iteratora? [Przykład na żywo] (http://coliru.stacked-crooked.com/a/3547c063ddfb1ddb) – dyp

+0

@dyp Byłem głupi, 'back_insert_iterator' ma zagnieżdżony typedef' container_type' nawet – TemplateRex

+0

Zobacz ostatnio dodany przykład na żywo. - ooooh, który jest członkiem publicznym. Widzę – dyp

Odpowiedz

6

Odpowiedź przez @Rapptz jest poprawna, ale dla kodu generycznego (czyli gdy nie jest jasne, a priori, czy ktoś zajmuje się surowy T* lub jeden z innych iteratorów wyjścia Biblioteki Standardowej), konieczne jest bardziej systematyczne podejście.

W tym celu poniżej definicji szablonu klasy output_iterator_traits w zdefiniowanej przez użytkownika 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 

Wersja niewyspecjalizowanych prostu dziedziczy std::iterator_traits<T>, ale za 6 iteratorów wyjściowych określonych w nagłówkach <iterator> i <memory>, że specjalizacje dziedziczą std::iterator<std::output_iterator_tag, V> gdzie V jest typem pojawiające się jako argument iterator na operator=(const V&).

Dla iteratorami wkładki odpowiada to typename Container::value_type, surowych iteratorami przechowywania do T, a ostream i ostreambuf iteratorami do T i charT, odpowiednio.

Ogólny algorytm postaci

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 */ }; 
    } 
} 

wtedy transparantly współpracować zarówno surowych wskaźników i iteratory wyjściowych Biblioteki standardu.

2

mógłby po prostu użyć container_type że posiada:

#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