3

私は、入力ストリームから単語を抽出するように設計された一種のistream_iterator(それを呼ぶ)設計をしています。my_istream_iteratorイテレータから抽出された単語が処理される方法は、単語がストリームで区切られる方法とは無関係ですが、単語自体は多くの形式の1つに従う場合があります。これに対応するために、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

std::istream_iterator<T>を使用するため、タスクに独自Tのistreamイテレータを作成する必要はありません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ための適切なコンストラクターを記述します。ポリシーをstd::shared_ptrに保持するか、その存続期間を管理するために何か他のことを行う必要があることに注意してください。my_istream_iteratorifstreammy_istream_policy_base*

特に効率的ではありませんが、作成と使用は比較的簡単です。

于 2011-08-02T05:33:52.810 に答える