std :: copyを使用して任意の数の値を読み取る方法
-
05-07-2019 - |
質問
これと反対のアクションをコーディングしようとしています:
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() ) );
しかし、私は 'end'イテレータにこだわっています-入力インターレータはstd :: advanceを使用できず、同じソースで2つのストリームを使用することもできません...
これを解決するエレガントな方法はありますか?もちろんforループを使用できますが、もっと良いものがあるかもしれません:)
解決
istream_iterator <!> lt; T <!> gt;から派生できます。
Daeminジェネレーター方式は別のオプションですただし、中間ベクトルを使用するのではなく、セットに直接生成します。
#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())
);
}
他のヒント
使用:
std::copy( std::istream_iterator<int>(ins),
std::istream_iterator<int>(),
std::inserter(my_set, my_set.end())
);
空のパラメーターに注意してください:
std::istream_iterator<int>();
エラー... copy_n()アルゴリズム?
これを少し見てみると、実際に要素を追加するためにinsertを呼び出す必要があるため、セットを直接読み取ることは機能するとは思いません(私は間違っているかもしれませんが、ここではかなり早朝です)。 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());
うまくいけば、それはあなたの問題を解決するか、物事の壮大な計画においてループがそれほど悪くないことをあなたに確信させた。
代替イテレータを使用してトラバースを行い、関数オブジェクト(またはラムダ)を使用してコンテナを埋める方法はどうですか?
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 <!> lt; <!> gt;' Boost.Iterator の一部です。
またはこれを行うことができます:
my_set.insert(std::istream_iterator<int>(ins), std::istream_iterator<int>());
はいsdgですが、そのファイル/ストリームで別のデータ構造を使用したい場合は?おそらくここに明示的に書き込む必要があります。このセットの後に別のものを保存したいので、これもサイズを保存している理由です。
(編集:質問をもっと読むべきだった...)
やや疑わしいものの、ファイルに<!> quot; fail <!> quot;というエントリを含めることで、ほぼ正しい動作を得ることができます。最初のループ、次にストリームの失敗ビットをクリアし、さらに読み取りを開始します。
明示的なサイズなしのデータ、ただしこのように
1 1 2 3 5 8 Fibb
少なくともVS2005とSTLPortでは、以下のコードを入力すると、意図したとおりに動作するようです。
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;