3

我正在设计一种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;
4

2 回答 2

2

对于您的任务,无需构建自己的 istream 迭代器,因为std::istream_iterator<T>使用T's 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));
}
于 2011-08-02T08:03:34.097 回答
1

类似于以下内容:

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获取 aifstream和 a my_istream_policy_base*。请注意,您需要将策略保存在 std::shared_ptr 中或执行其他操作来管理其生命周期。

效率不是特别高,但相对容易编写和使用。

于 2011-08-02T05:33:52.810 回答