使用std :: istream_iterator限制std :: copy的范围

Fle*_*exo 23 c++ iterator stl istream-iterator

我构建了一个最小的工作示例来显示我使用STL迭代器遇到的问题.我正在使用istream_iterator以下内容读取floatss(或其他类型)std::istream:

#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
   float values[4];
   std::copy(std::istream_iterator<float>(std::cin), std::istream_iterator<float>(), values);
   std::cout << "Read exactly 4 floats" << std::endl; // Not true!
}
Run Code Online (Sandbox Code Playgroud)

这将读取所有可能的floatss,直到EOF为values固定大小,4,所以现在显然我想限制范围以避免溢出并准确读取/最多4个值.

使用更多"正常"迭代器(即RandomAccessIterator),提供begin+4的不是你要做的结束:

std::copy(begin, begin+4, out);
Run Code Online (Sandbox Code Playgroud)

准确阅读4个元素.

如何做到这一点std::istream_iterator?显而易见的想法是将呼叫更改std::copy为:

std::copy(std::istream_iterator<float>(std::cin), std::istream_iterator<float>(std::cin)+4, values);
Run Code Online (Sandbox Code Playgroud)

但(相当可以预见)这不编译,没有候选人operator+:

g++ -Wall -Wextra test.cc
test.cc: In function ‘int main()’:
test.cc:7: error: no match for ‘operator+’ in ‘std::istream_iterator<float, char, std::char_traits<char>, long int>(((std::basic_istream<char, std::char_traits<char> >&)(& std::cin))) + 4’
Run Code Online (Sandbox Code Playgroud)

有什么建议?是否有正确的"STLified"前C++ 0x方法来实现这一目标?显然我可以把它写成for循环,但我想在这里学习一些关于STL的东西.我半想知道滥用std::transformstd::merge等以某种方式实现这一功能,但我不能完全看到如何做到这一点.

ild*_*arn 14

当您请求非C++ 0x解决方案时,这里有一个使用std::generate_n和生成器函数而不是std::copy_n迭代器的替代方法:

#include <algorithm>
#include <string>
#include <istream>
#include <ostream>
#include <iostream>

template<
    typename ResultT,
    typename CharT = char,
    typename CharTraitsT = std::char_traits<CharT>
>
struct input_generator
{
    typedef ResultT result_type;

    explicit input_generator(std::basic_istream<CharT, CharTraitsT>& input)
      : input_(&input)
    { }

    ResultT operator ()() const
    {
        // value-initialize so primitives like float
        // have a defined value if extraction fails
        ResultT v((ResultT()));
        *input_ >> v;
        return v;
    }

private:
    std::basic_istream<CharT, CharTraitsT>* input_;
};

template<typename ResultT, typename CharT, typename CharTraitsT>
inline input_generator<ResultT, CharT, CharTraitsT> make_input_generator(
    std::basic_istream<CharT, CharTraitsT>& input
)
{
    return input_generator<ResultT, CharT, CharTraitsT>(input);
}

int main()
{
    float values[4];
    std::generate_n(values, 4, make_input_generator<float>(std::cin));
    std::cout << "Read exactly 4 floats" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

如果你愿意,你可以结合使用这个生成器boost::generator_iterator来使用生成器作为输入迭代器.

  • 有意思的是,`generate_n`保证只执行`n`调用`operator()`,因此你没有'copy_n`可能出现的计数问题.另外,如果专门用于`std :: cin`,可以避免谓词并使用一个简单的函数(`template <typename T> T get(){T t = T(); std :: cin >> t; return t;}`).此外,它允许轻松检查输入的状态(`std :: cin`). (2认同)

Igo*_*nko 13

看一眼 std::copy_n 

  • @ildjarn:`advance`适用于InputIterator,但你不能用它构建一个范围. (4认同)
  • @Igor Nazarenko:一般,但你应该注意到这个算法是C++ 0x的新算法,并不适用于较旧的编译器的标准库. (3认同)
  • 使用copy_n有自己的问题,它增加了istream_iterator的次数[http://stackoverflow.com/questions/5074122/stdistream-iterator-with-copy-n-and-friends](http://stackoverflow. com/questions/5074122/stdistream-iterator-with-copy-n-and-friends)在这种情况下,它可能会复制4个浮点数,但*可能*也会从cin读取5个! (3认同)
  • @ildjarn:来自@awoodland post,他试图使用它,以便他可以为`copy`算法指定一个"适当的"范围.除了使用RandomAccessIterator(无论是使用`+`还是`advance`),你不能在没有实际读取整个范围的情况下构建一个合适的范围. (2认同)