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.
Dlaczego nie używasz typu zagnieżdżonego pochodzącego z iteratora? [Przykład na żywo] (http://coliru.stacked-crooked.com/a/3547c063ddfb1ddb) – dyp
@dyp Byłem głupi, 'back_insert_iterator' ma zagnieżdżony typedef' container_type' nawet – TemplateRex
Zobacz ostatnio dodany przykład na żywo. - ooooh, który jest członkiem publicznym. Widzę – dyp