2015-03-15 2 views
6

std::back_insert_iterator имеет value_type, равную void, но он также имеет protected элемент container, который содержит указатель на нижележащей Container. Я пытаюсь написать черты класса для извлечения контейнера value_type, вдоль этих линий:Черты характера класса для извлечения value_type контейнера из 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

Однако это (более или менее ожидаемо) впадает в ошибки неполного типа. В любом случае, чтобы получить экстракт контейнера value_type?

+0

Почему вы не используете вложенный тип, который происходит от итератора? [Живой пример] (http://coliru.stacked-crooked.com/a/3547c063ddfb1ddb) – dyp

+0

@ dyp Я был глупым, 'back_insert_iterator' имеет вложенный typedef' container_type' даже – TemplateRex

+0

См. Недавно добавленный живой пример. - ooooh, который является публичным участником. Я вижу – dyp

ответ

6

Ответ на @Rapptz является правильным, но для общего кода (то есть, когда не ясно априори ли идет речь о raw T* или back_insert_iterator или один из других выходных итераторов стандартной библиотеки), необходим более систематический подход.

Для этого под определением шаблона класса output_iterator_traits в пользовательском 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 

неспециализированных версия просто наследует от std::iterator_traits<T>, но для 6 выходных итераторов, определенных в заголовках <iterator> и <memory>, специализации наследуют от std::iterator<std::output_iterator_tag, V>, где V является типом появляться в качестве аргумента итератора operator=(const V&).

Для вставки итераторов, это соответствует typename Container::value_type, для хранения сырых итераторов для T, так и для ostream и ostreambuf итераторов в T и charT, соответственно.

Общий алгоритм вида

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

будет работать прозрачно с обоих исходных указателей и выходных итераторов стандартной библиотеки.

2

Вы могли бы просто использовать container_type, что у него есть:

#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

Смежные вопросы