Избавление пользователя от указания параметра шаблона политики - PullRequest
3 голосов
/ 02 августа 2011

Я создаю вид istream_iterator (назовите его my_istream_iterator), предназначенный для извлечения слов из входного потока. То, как будут обрабатываться слова, извлеченные из итератора, не зависит от того, как слова разграничиваются в потоке, но сами слова могут иметь один из многих форматов. Для этого я хочу, чтобы пользователь мог указать класс политики при создании my_istream_iterator с использованием входного потока, при этом пользователю не нужно указывать тип класса политики в списке аргументов шаблона итератора. Например, если я хочу выводить записи в CSV-файле в главном порядке строк, я хотел бы иметь возможность сделать что-то вроде этого:

std::ifstream is("words.csv");

// Assume that the_policy_class is used to read a special kind
// of CSV file that deviates from the standard specification.

// I don't want to have to specify the type of the policy class
// used by the iterator; how would I be able to do this? (The
// value_type of `mystream_iterator` is always char*).
my_istream_iterator begin = csv_begin<the_policy_class>(
    is, the_policy_class('\t', '\n', 1));

// Default constructor for end-of-stream iterator.
my_istream_iterator end;

std::ostream_iterator<char*> out(std::cout, ", ");

// Print the words, delimited by commas, to stdout.
std::copy(begin, end, out);

Как можно сэкономить пользовательскую форму, указав тип класса политики при создании mystream_iterator, даже если класс политики внутренне используется итератором? Возможно ли это?

Спасибо за вашу помощь!

<ч />

Если это поможет, определение класса my_istream_iterator, скорее всего, будет выглядеть примерно так:

template <typename Character, typename CharTraits = std::char_traits<Character>,
    typename Distance = std::ptrdiff_t>
class basic_my_istream_iterator : public std::iterator<std::input_iterator_tag,
    const Character*, Distance>
{
      /* ... */  
};

typedef basic_my_istream_iterator<char> my_istream_iterator;
typedef basic_my_istream_iterator<wchar_t> my_wistream_iterator;

Ответы [ 2 ]

2 голосов
/ 02 августа 2011

Для вашей задачи нет необходимости создавать собственный итератор istream, поскольку std::istream_iterator<T> использует T operator<<(). Например:

#include <iostream>
#include <iterator>
#include <vector>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

template<char field_delim, char row_delim>
struct csv_row
{
    std::vector<std::string> fields;

    friend std::istream& operator>>(std::istream& s, csv_row& row)
    {
        std::string line;
        getline(s, line, row_delim);
        char field_delim2[2] = { field_delim };
        boost::split(row.fields, line, boost::is_any_of(field_delim2));
        return s;
    }

    friend std::ostream& operator<<(std::ostream& s, csv_row const& row)
    {
        // hard-code tab-separated output just for the sake of exposition
        std::copy(row.fields.begin(), row.fields.end(), std::ostream_iterator<std::string>(s, "\t"));
        return s << '\n';
    }
};

int main()
{
    typedef csv_row<'|', '\n'> row;
    std::vector<row> rows;
    std::copy(std::istream_iterator<row>(std::cin), std::istream_iterator<row>(), std::back_inserter(rows));
    std::copy(rows.begin(), rows.end(), std::ostream_iterator<row>(std::cout));
}
1 голос
/ 02 августа 2011

Что-то вроде следующего:

class my_istream_policy_base {
  virtual ~my_istream_policy_base() = 0;
  virtual char* find_next_break(char*, size_t) = 0;
}

template<typename T>
my_istream_iterator csv_begin(std::ifstream is, T pol) {
  return my_istream_iterator(is, new T(pol));
}

Затем просто убедитесь, что каждая политика наследуется от my_istream_policy_wrapper_base, и напишите соответствующий конструктор для my_istream_iterator, взяв ifstream и my_istream_policy_base*. Обратите внимание, что вам нужно сохранить политику в std :: shared_ptr или сделать что-то еще, чтобы управлять ее временем жизни.

Не особенно эффективно, но относительно легко написать и использовать.

...