从stringstream插入并带有隐含转换

时间:2016-10-31 08:24:28

标签: c++ implicit-conversion stringstream

我正在从ASCII文件中读取科学记数法中以空格分隔的单精度值。每行有多个值。我通过streamstream填充向量;向量的原始类型可能与数据类型不同:

// Illustrates typical string from file
std::string string_with_floats("-2.750000e+001 2.750000e+001 3.450000e+001");

// Template parameter is the desired return type
vector<int> data = ReadValues<int>(string_with_floats);

template <class T>
vector<T>& ReadValues(std::string& string_with_data)
{
    std::stringstream ss(string_with_data);
    std::vector<T> values;
    T val;
    while(stream >> val)
    {
        values.push_back(val);
    }
    return values;
}

上面的示例导致向量仅填充第一个值,截断为-2,可能是因为一旦遇到非数字字符,循环就会终止。当传入的字符串包含int值时,它会按预期工作,即使模板参数是float。

有没有办法配置字符串流来执行隐式转换并舍入到最接近的整数,或者我是否需要先插入原始基本类型(浮点数)并对T执行显式转换?理想情况下,我不想告诉ReadValues有关string_with_data中数据的类型 - 它总是double,float,int,short或long之一,请求的类型也可以是这些类型中的任何一种。 / p>

感谢。

2 个答案:

答案 0 :(得分:1)

如果您知道string_with_data中数据的类型,那么它会更简单:只需读取该类型的一个值,然后将其转换为所需类型,然后再将其推入向量:

template <class T>
vector<T>& ReadValues(std::string& string_with_data)
{
    std::stringstream ss(string_with_data);
    std::vector<T> values;
    float val; // use original type not required one
    while(stream >> val)
    {
        values.push_back((T) val);
    }
    return values;
}

如果您不知道原始类型,则会更难一些,因为C ++中没有单一类型,标准库中也没有足够接受所有其他类型的类型。因此,您必须将每个数据作为字符串读取,然后使用辅助字符串流将其解码为所需类型:

template <class T>
std::vector<T> ReadValues(std::string& string_with_data)
{
    std::stringstream ss(string_with_data);
    std::vector<T> values;
    std::string str;
    T val;
    while(ss >> str)         // first store the value into a string whatever it is
    {
        std::stringstream(str) >> val;   // then read it as the required type
        values.push_back(val);
    }
    return values;
}

这样你就可以确定:

  • 在读取int
  • 时,您没有在流中留下浮动的尾部
  • 在阅读原始字符串时使用所需类型允许的最大精度

注意:我假设您接受默认转换...

答案 1 :(得分:0)

为什么不直接从文件中提取数据作为浮点数,而不是获取第一行,然后浮点数,然后是整数?

double f;
std::vector<int> out;
std::ifstream file("numbers.txt");

file >> std::scientific;

while (file >> f)
    out.push_back(out);

或者如果你想做更多的迭代器友好:

std::vector<int> out;
std::ifstream file("numbers.txt");

file >> std::scientific;

std::copy(std::istream_iterator<double>(file), 
          std::istream_iterator<double>(),
          std::back_inserter(out)));

如果像@SergeBallesta所说的那样,你想要一个泛型函数,你不知道“原始”类型,只有目标类型,就像迭代器一样:

template <class T>
std::vector<T> ReadValues(std::string& string_with_data)
{
  std::istringstream ss(string_with_data);
  std::vector<T> values;

  using iss_it = std::istream_iterator<std::string>;

  std::transform(iss_it(string_with_data), iss_it(), std::back_inserter(values),
                 [](const std::string& x) { return boost::lexical_cast<T>(x) });

  return values;
}