转换字符串标记流时如何避免重复的istringstream构造

时间:2016-04-12 11:30:45

标签: c++ c++11 tostring generic-programming lexical-cast

我(打算)使用this answer中的代码从CSV中读取内容。基本上我得到连续,个字符之间的字符串的迭代器;但是我没有将它们放在字符串向量中,而是将这些字符串解析为(任意)类型T的元素,这些元素来自模板参数。所以......

template <typename T>
void foo(const std::string& line) 
{
    // ....
    std::vector<T> vec;
    using namespace boost;
    tokenizer<escaped_list_separator<char> > tk(
       line, escaped_list_separator<char>('\\', ',', '\"'));
    for (tokenizer<escaped_list_separator<char> >::iterator i(tk.begin());
       i!=tk.end();++i) 
    {
       /* magic goes here */
    }

我可以使用istringstream`(例如建议的here):

std::istringstream iss(*i);
T t; iss >> t;
vec.push_back(t);

但这太过分了(我可能会在这里建造两次甚至三次)。如果C ++的std::from_string()与其std::to_string类似,那么我只会做

vec.emplace_back(std::from_string(*i));

但这并不存在。也许boost::lexical_cast?我真的宁愿使用标准的东西。

我该怎么办?

1 个答案:

答案 0 :(得分:0)

制作istringstream static thread_local

T parse (const string& line){
  static thread_local istringstream stream;
  stream.str(""); //flush the stream
  //keep using stream
}

如果您的应用程序是单线程的,则可以放弃thread_local

其他不涉及将流静态保存到函数的解决方案是使用Parser对象包装流,并继续使用该对象,使用str刷新内部缓冲区

class Parser{
  std::stringstream stream;
  public:
  void parse(const std::string& data){
     stream.str("");
     // the rest
  }

}

Parser parser;
parser.parse("my,data");
parser.parse("other,data");

编辑: 为了防止每个T类型的实例化,将流封装在不同的函数中, 创建一个辅助函数,构造std::istringstream一次构成每个线程:

namespace detail {
istringstream& getStream(){
      static thread_local istringstream stream;
      stream.str("");
      return stream;
}
} // namespace detail

template<class T>
void parse(){
   auto& stream = detail::getStream();
   //do soemthing with stream

}