用流读取复杂的结构

Reading complex structures with streams

本文关键字:结构 复杂 读取      更新时间:2023-10-16

考虑我有以下"一对浮点数"对象输入格式:(第一个变量,第二个变量)例如(1.0,15.6)。

读这种结构体的最好方法是什么?在C中,我会使用scanf("(%f, %f)", &var1, &var2) -很好,不是吗?(是的,我知道它不提供类型安全等)

但是我知道使用c++流只有一种方法:

float var1, var2;
char tmp;
cin >> tmp;
cin >> var1;
cin >> tmp;
cin >> var2;
cin >> tmp;

看起来很丑,它只是一对浮点数。那么,有没有一种优雅的方式来做到这一点呢?像

cin >> "(" >> var1 >> ", " >> var2 >> ")";

可能是Boost。精神是你能找到的最接近的东西。下面是一个如何使用它来达到你想要的效果的例子。

我会写一个输入操作符:
从@Seth Carnegie那里偷来FloatPair。

因此输入现在看起来正常:

FloatPair c;
std::cin >> c;

我想让它看起来像这样。

std::istream& operator>>(std::istream& stream, FloatPair& out)
{
    return stream >> I('(') >> out.a >> I(',') >> out.b >> I(')');
}

然后我有一个像这样的忽略对象。
如果您愿意,可以简单地进行模板化。为了使代码更简单,我把我的代码命名为I

template<typename T>
struct ignore
{
    T ignoreItem;
    ignore(T const& x): ignoreItem(x) {}
};
template<typename T>
ignore<T> I(T const& x) { return ignore<T>(x);}  // This is where I in the above code comes from.

则忽略的输入操作符>>如下所示:

std::istream& operator>>(std::istream& stream, ignore<T> const& test)
{
    T   next;
    if ((stream >> next) && (test.ignoreItem != next))       // if the stream already failed
    {    stream.setstate(std::ios::badbit);                 // then don't change anything
    }                                                       // as it may confuse people
    return stream;
}

string的专门化。处理操作符>>在string上只读取一个单词的事实。
注意:在scanf()中,一个空格匹配1个或多个空格。因此,如果输入字符串中有空格,则遵循相同的规则。

template<>
struct ignore<std::string>
{
    std::vector<std::string> ignoreItemVector;
    ignore(std::string const& x)
    {
        // Split the input into a list of words to ignore.
        std::stringstream  words(x);
        std::copy(std::istream_iterator<std::string>(words),
                std::istream_iterator<std::string>(words),
                std::back_inserter(ignoreItemVector)
                );
    }
};
template<>
std::istream& operator>><std::string>(std::istream& stream, ignore<std::string> const& test)
{
    // Specifically ignore each word.
    foreach(std::string const& loop, test.ignoreItemVector)
    {
        std::string   next;
        if ((stream >> next) && (loop != next))       // if the stream already failed
        {    stream.setstate(std::ios::badbit);      // then don't change anything
        }                                            // as it may confuse people
    }
    return stream;
}

我要做的是创建一个类来表示一对浮点数:

class FloatPair {
public:
    FloatPair() : a(), b() { }
    float a, b;
};

和重载operator>>来处理流:

istream& operator>>(istream& rhs, FloatPair& out) {
    rhs.ignore(256, '(');
    rhs >> out.a;
    rhs.ignore(256, ' ');
    rhs >> out.b;
    rhs.ignore(256, ')');
    return rhs;
}

所以你可以直接输入FloatPair:

FloatPair fp1, fp2;
cin >> fp1 >> fp2;

这有点脆弱,因为如果你在输入中有非常偏离(float, float)的格式,它将会中断。