C++ 避免用户指定策略模板参数

C++ 避免用户指定策略模板参数,c++,templates,design-patterns,iterator,istream-iterator,C++,Templates,Design Patterns,Iterator,Istream Iterator,我正在设计一种istream\u迭代器(称之为myistream\u迭代器),用于从输入流中提取单词。处理从迭代器中提取的单词的方式与在流中分隔单词的方式无关,但是单词本身可能遵循多种格式之一。为了适应这种情况,我希望用户能够在使用输入流创建my_istream\u迭代器时指定策略类,而无需用户在迭代器的模板参数列表中指定策略类的类型。例如,如果我想以行主顺序输出CSV文件中的条目,我希望能够执行以下操作: std::ifstream is("words.csv"); // Assume th

我正在设计一种
istream\u迭代器
(称之为
myistream\u迭代器
),用于从输入流中提取单词。处理从迭代器中提取的单词的方式与在流中分隔单词的方式无关,但是单词本身可能遵循多种格式之一。为了适应这种情况,我希望用户能够在使用输入流创建
my_istream\u迭代器时指定策略类,而无需用户在迭代器的模板参数列表中指定策略类的类型。例如,如果我想以行主顺序输出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);
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;

如下所示:

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));
}
class my\u istream\u policy\u base{
virtual~my\u istream\u policy\u base()=0;
虚拟字符*查找下一个中断(字符*,大小=0;
}
模板
my_istream_迭代器csv_begin(std::ifstream is,T pol){
返回my_istream_迭代器(is,newt(pol));
}
然后确保每个策略都继承自
myistream\u policy\u wrapper\u base
,并为
myistream\u迭代器
编写一个合适的构造函数,使用
ifstream
myistream\u policy\u base*
。请注意,您需要将策略保存在std::shared_ptr中,或者执行其他操作来管理其生存期


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

对于您的任务,不需要构建自己的istream迭代器,因为
std::istream\u迭代器
使用
T
操作符(std::istream&s,csv\u row&row)
{
std::字符串行;
getline(s、line、row_delim);
char field_delim2[2]={field_delim};
boost::split(row.fields,line,boost::是(field_delim2)中的任意一个);
返回s;
}

friend std::ostream&operatorI曾考虑过使用虚拟函数,但我将使用流读取以GB为单位的此类数据,因此我希望避免开销;我应该在问题中提到这一点。我想知道这是否仍然是可能的;我认为必须在某个地方明确提到类型,编译器才能推断出要调用的正确函数。从根本上说,如果my_istream_迭代器不接受类型参数,则只有一个my_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));
}