2017-01-16 99 views
0

我想一个通用的,完全符合istream的“提取运算符”是这样的:如何实现运算符>>(std :: istream&,std :: array <char, N>&)?

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更简单,则可以使用Boost。

+1

我相信你肯定发现了一次只读一个字符的方法有问题,然后保持计数以检查溢出。 – Arunmu

+0

@JohnZwinck我想你应该用一些边缘案例来说明你想要的确切行为,例如''a b c“','”abc“'。 – Holt

+0

@Holt:我想要的行为与使用'std :: string'而不是'std :: array '完全相同的行为,如果字符串不适合内部N包括空终止符,那么添加一个设置失败。其余的行为和所有的边缘情况应该像普通的C++字符串一样处理。 –

回答

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] 
+0

谢谢你。你可以让它做空终止,包括如果输入流为空或失败,将零作为第一个字符? –

+0

这里存在一个重要的错误:遇到空白(没有noskipws)时它不停止。常规的'std :: string'运算符也这样做,这也应该。 –

+0

@JohnZwinck当你说“bug”时,这意味着当遇到这些情况时你有一些定义好的行为。编写此代码时我并不知道这些要求(您看到用户和实现者之间的常年问题?)。 如果您正式声明您的要求,我可以构建一个测试套件来检查它们,然后相应地重复此代码直到我们通过。这一切都始于知道并说明你想要的行为。 –

1

不是一个完整的答案,但过大的评论:

重载运营商,其唯一的操作数在namespace std会导致使困难。这是因为两阶段查找,任何其他自定义operator>>都会隐藏你的一个,see example

正常情况下,通过在与其中一个操作数相同的命名空间中定义重载操作符可避免此问题,因此依赖于参数的查找始终会查找操作符。 (ADL仍然搜索包含的名称空间,即使更近的名称空间有名字)。

但是,该解决方案不适用于您,因为它是undefined behaviour to add your own functions to namespace std

我不确定此问题的首选解决方法是什么。如果您希望通过模板参数使用>>通用模板代码找到此功能,则需要明确地使您的超载可见,同一函数内的using ::operator>>;调用操作符。或者也许更整齐,using mystuff::operator>>你把你的东西放在自己的名字空间。

+0

哎唷!那么,在我的特殊情况下,我愿意并能够在我自己的命名空间中为'std :: array'使用typedef或包装类。所以我想我可以解决这个问题,但这是一个愚蠢的,所以感谢指出! –

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; 
} 

据我所知,它的行为像您的版本,但它从不读取超过N - 1字符std::basic_string

相关问题