如何实现运算符&gt;&gt;(std :: istream&amp;,std :: array <char,n =“”>&amp;)?

时间:2017-01-16 09:51:35

标签: c++ operator-overloading iostream istream

我想要一个通用的,完全兼容的istream&#34;提取运算符&#34;像这样:

template <typename CharT, size_t N, class Traits>
std::basic_istream<CharT, Traits>& operator>>(
    std::basic_istream<CharT, Traits>& in,
    std::array<CharT, N>& out)
{
    std::basic_string<CharT, Traits> buf; // this is not great
    in >> buf;
    if (buf.size() >= N) {
        in.setstate(std::ios::failbit); // is this the right thing to do?
        out[0] = 0;
    } else {
        std::copy(buf.begin(), buf.end(), out.data());
        out[buf.size()] = 0;
    }

    return in;
}

但是这会不必要地分配和复制内存。我想避免这种情况。但我也希望保留完整的功能,包括适当的空格和对std::noskipws等的支持。如果它更容易使用Boost就行了。

3 个答案:

答案 0 :(得分:1)

不是一个完整的答案,但对评论来说太大了:

重载只有namespace std操作数的运算符会导致问题。这是因为两阶段查找,任何其他自定义operator>>都会隐藏您的see example

通常,通过在与其中一个操作数相同的命名空间中定义重载运算符来避免此问题,因此依赖于参数的查找始终会找到运算符。 (即使更近的命名空间具有名称,ADL仍会搜索封闭的命名空间。)

但是,您无法使用该解决方案,因为它是undefined behaviour to add your own functions to namespace std

我不确定这个问题的首选解决方法是什么。如果您希望在模板参数上使用>>通用模板代码找到此函数,则需要在调用运算符的同一函数内使用using ::operator>>;显式使您的重载可见。或者更整齐,using mystuff::operator>>你把你的东西放在自己的名字空间里。

答案 1 :(得分:1)

以下内容应该有效:

template <typename CharT, size_t N, class Traits>
std::basic_istream<CharT, Traits>& operator>>(
    std::basic_istream<CharT, Traits>& in,
    std::array<CharT, N>& out)
{
    in >> std::setw(N) >> out.data();
    if (!in.eof() && !std::isspace((CharT)in.peek(), in.getloc())) {
        out[0] = 0;
        in.setstate(in.rdstate() | std::ios::failbit);
    }
    return in;
}

据我所知,它的行为与std::basic_string的版本相同,只是它的读取次数绝不会超过N - 1

答案 2 :(得分:0)

这样的事情:

#include <array>
#include <istream>
#include <sstream>

template <typename CharT, size_t N, class Traits>
std::basic_istream<CharT, Traits>& operator>>(
    std::basic_istream<CharT, Traits>& in,
    std::array<CharT, N>& out)
{
    auto first = out.begin();
    auto last = out.end();
    while (first != last and in)
    {
        in >> *first++;
    }
    return in;
}

int main()
{
    std::istringstream ss { "a cd" };
    ss >> std::noskipws;

    std::array<char, 4> a;
    ss >> a;

    for (char c : a) {
        std::cout << "[" << c << "]\n";
    }
}

结果:

[a]
[ ]
[c]
[d]