2008-10-30 58 views
8

我试图代码相反的动作这样的:如何使用std :: copy读取任意数量的值?

std::ostream outs; // properly initialized of course 
std::set<int> my_set; // ditto 

outs << my_set.size(); 
std::copy(my_set.begin(), my_set.end(), std::ostream_iterator<int>(outs)); 

它应该是这样的:

std::istream ins; 

std::set<int>::size_type size; 
ins >> size; 

std::copy(std::istream_iterator<int>(ins), std::istream_iterator<int>(ins) ???, std::inserter(my_set, my_set.end())); 

但我坚持的“结束”迭代器 - 输入interators能不使用std :: advance,也不能使用两个源码相同的流...

有没有什么优雅的方法来解决这个问题?当然,我可以使用循环,但也许有一些更好:)

回答

3

您可以从istream_iterator <T>中派生出来。
虽然使用Daemin generator method是另一种选择,但我会直接生成集合而不是使用中间向量。

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


template<typename T> 
struct CountIter: public std::istream_iterator<T> 
{ 
    CountIter(size_t c) 
     :std::istream_iterator<T>() 
     ,count(c) 
    {} 
    CountIter(std::istream& str) 
     :std::istream_iterator<T>(str) 
     ,count(0) 
    {} 

    bool operator!=(CountIter const& rhs) const 
    { 
     return (count != rhs.count) && (dynamic_cast<std::istream_iterator<T> const&>(*this) != rhs); 
    } 
    T operator*() 
    { 
     ++count; 
     return std::istream_iterator<T>::operator*(); 
    } 

    private: 
     size_t count; 
}; 

int main() 
{ 
    std::set<int>  x; 

    //std::copy(std::istream_iterator<int>(std::cin),std::istream_iterator<int>(),std::inserter(x,x.end())); 
    std::copy(
       CountIter<int>(std::cin), 
       CountIter<int>(5), 
       std::inserter(x,x.end()) 
      ); 
} 
0

(编辑:我应该读的问题接近...)

虽然有点怀疑,你可以有大约得到正确的行为该文件中的一个条目将使第一个循环“失败”,然后清除流上的故障位并开始读取更多。

数据,没有一个明确的大小,但这样

 
1 1 2 3 5 8 Fibb 

美联储将下面的代码似乎做了我的意思,至少在与STLPort的VS2005。

 
typedef std::istream_iterator < int, char, std::char_traits ,ptrdiff_t> is_iter; 
std::copy(is_iter(cin), is_iter(), inserter(my_set,my_set.end())); 
cin.clear(); 
std::cin >> instr; 
+0

呵呵,你说得对,它是一种怀疑和最重要的 - 它不会在二进制流:) – 2008-10-30 14:01:10

0

是sdg,但是当我想在该文件/流中使用其他数据结构?我应该明确地写在这里,我想在这个集合之后存储另一个东西,这也是我存储大小的原因。

2

错误... copy_n()算法?

+0

“这个功能是一个SGI扩展;它不是C++标准的一部分。“ 这是非常真实的,它至少在VS2008中缺少。但很好,我几乎想责怪自己怎么可能忽略它;) – 2008-10-30 14:00:02

+1

C++ 0x是 – 2008-12-11 20:07:32

2

看着这一点,我不认为直接读入一个集合会起作用,因为你需要调用插入来实际添加元素(我可能会误解,这是在凌晨这里) 。虽然看着VS2005的STL文件简要我认为使用generate_n功能应该工作的东西,比如:

std::istream ins; 
std::set<int> my_set; 
std::vector<int> my_vec; 

struct read_functor 
{ 
    read_functor(std::istream& stream) : 
     m_stream(stream) 
    { 
    } 

    int operator() 
    { 
     int temp; 
     m_stream >> temp; 
     return temp; 
    } 
private: 
    std::istream& m_stream; 
}; 

std::set<int>::size_type size; 
ins >> size; 
my_vec.reserve(size); 

std::generate_n(my_vec.begin(), size, read_functor(ins)); 
my_set.insert(my_vec.begin(), my_vec.end()); 

希望这要么解决你的问题,或使你确信环路是不是在隆重的那么糟糕事物的计划。

+1

为什么使用向量作为中间函数?只需使用生成器插入集合(使用std :: inserter)。 – 2008-10-30 15:41:27

+0

当我编写答案时已经很晚了,当时它并没有想到。我想你会使用插件,但它仍然需要创建一个完整的其他类,所以对于我来说,循环会更简单,可能看起来更好。 – Daemin 2008-10-30 22:27:06

1

如何使用备用迭代器进行遍历,然后使用函数对象(或lambda)来填充容器?

istream ins; 
set<int>::size_type size; 
set<int> new_set; 
ins >> size; 
ostream_iterator<int> ins_iter(ins); 

for_each(counting_iterator<int>(0), counting_iterator<int>(size), 
    [&new_set, &ins_iter](int n) { new_set.insert(*ins_iter++); } 
); 

当然,这里假定你有一个C++ 0x兼容的编译器。

顺便说一句,'counting_iterator <>'是Boost.Iterator的一部分。

0

感谢您的想法家伙。即使这些事情看起来很酷,我当然不会为创建新类/迭代器,它;-)我更好地理解为什么SGI决定将现在的“copy_n”算法:)

3

用途:

std::copy(std::istream_iterator<int>(ins), 
      std::istream_iterator<int>(), 
      std::inserter(my_set, my_set.end()) 
     ); 

注意空参数:

std::istream_iterator<int>(); 
1

或者你可以这样做:

my_set.insert(std::istream_iterator<int>(ins), std::istream_iterator<int>());