2016-04-12 2 views
2

Я (намереваясь) использовать код в this answer, чтобы прочитать что-то из CSV. По сути, я получаю итератор для строк между последовательными , символами; но вместо того, чтобы помещать их в вектор строк, я хочу проанализировать эти строки на элементы (произвольного) типа T, которые исходят из аргумента шаблона. Так что ...Как избежать повторяющейся конструкции istringstream при преобразовании потока токенов строки

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

только «общий» способ создать что-то как функция 'from_string' * есть * со строковыми потоками, и на самом деле работает' boost :: lexical_cast'. Конечно, он полагается на тип ('T', что бы это ни было), чтобы иметь соответствующую перегрузку' operator >> '. У вас могут быть специальные специализации для таких вещей, как номера, например, 'strtod' или' stoi'), но кроме этого нет возможности избежать сцеплений 'istringstream'. –

+0

Даже если существовала функция 'from_string', я не вижу, чтобы она делала большую часть улучшения производительности/пространства. Просто 2-3-х дополнительных операций, в результате чего общий O (n). Чистый код мудрый, вы можете просто инкапсулировать свой собственный шаблон 'from_string' через' sstream'. – aybassiouny

+0

@aybassiouny: 1. Вы имеете в виду from_string. 2. Строка istringstream, возможно, требует некоторой конструкции 3. Строка istringstream делает свое собственное подглядывание, токенизацию, сохраняя следующую неиспользованную позицию и т. Д., В то время как в моем случае я знаю, что во всей строке есть только одно значение. Я уверен, что в этом есть преимущество в производительности. – einpoklum

ответ

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"); 

EDIT: Для того, чтобы предотвратить instansiation для каждого T типа, инкапсулировать поток в Diferent функции, сделать вспомогательную функцию, которая строит 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 

} 
+0

Это опасное изображение Дэйва, которое у вас есть для аватара? – einpoklum

+0

yep. Я Дэйв. и я опасен :) –

+0

Подождите, ваша шаблонная функция синтаксиса даст мне отдельный объект istream для каждого значения T. Это не так хорошо ... как насчет неиспользуемой функции gettlength istringstream, которая сохраняет статическую переменную thread_local? Кроме того, является thread_local C++ 11? C++ 14? C++ 17? – einpoklum

Смежные вопросы