EOFに達したために読み取りが失敗した場合は、を設定したままclear(eofbit)
にする必要があるため、これは望ましくありません。failbit
それ以外の場合、eofbit
設定をそのままにしておくと、EOFに達した後に別の読み取りを試行するfailbit
などのループが発生し、その読み取りが再度設定されます。それがあなたを使用していた場合を除いて、それはそれをクリアし、そしてもう一度読んでみてください。そしてまた。そしてまた。ストリームの正しい動作は、EOFが原因で読み取りに失敗した場合に設定することなので、設定したままにしておきます。while (in >> s)
failbit
operator>>
failbit
イテレータとアルゴリズムを使用してこれを行うには、次のようなものが必要です。
copy_while(InputIter, InputIter, OutputIter, Pred);
これは、述語がtrueの場合にのみ入力シーケンスをコピーしますが、標準ライブラリには存在しません。あなたは確かにそれを書くことができます。
template<typename InputIter, typename OutputIter, typename Pred>
OutputIter
copy_while(InputIter begin, InputIter end, OutputIter result, Pred pred)
{
while (begin != end)
{
typename std::iterator_traits<InputIter>::value_type value = *begin;
if (!pred(value))
break;
*result = value;
result++;
begin++;
}
return result;
}
今、あなたはこのようにそれを使うことができます:
inline bool
is_valid_seq_char(char c)
{ return std::string("ACGT").find(c) != std::string::npos; }
inline std::istream&
operator>>(std::istream& in, seq& rhs)
{
copy_while(
std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::back_inserter(rhs),
&is_valid_seq_char);
return in;
}
int main()
{
std::istringstream istr("GATTACA FOO");
seq s;
assert((istr >> s) and s == "GATTACA");
}
これは機能しますが、問題は文字の読み取りにistream_iterator
使用operator>>
されるため、空白をスキップすることです。これは、後続のスペース"GATTACA"
がアルゴリズムによって消費されて破棄されることを意味するため、これを最後に追加するmain
と失敗します。
assert(istr.get() == ' ');
istreambuf_iterator
空白をスキップしないこの使用法を解決するには:
inline std::istream&
operator>>(std::istream& in, seq& rhs)
{
copy_while(
std::istreambuf_iterator<char>(in),
std::istreambuf_iterator<char>(),
std::back_inserter(rhs),
&is_valid_seq_char);
return in;
}
これを完了するには、抽出されたseq
場所に文字がない場合、抽出に失敗したことを示す必要があります。
inline std::istream&
operator>>(std::istream& in, seq& rhs)
{
copy_while( std::istreambuf_iterator<char>(in), {},
std::back_inserter(rhs), &is_valid_seq_char);
if (seq.empty())
in.setstate(std::ios::failbit); // no seq in stream
return in;
}
{}
その最終バージョンでは、最後のイテレータに使用することで、私のお気に入りのC++11トリックの1つを使用して少し単純化しています。の2番目の引数copy_while
の型は、最初の引数の型と同じである必要があります。これは、と推定されるstd::istreambuf_iterator<char>
ため、{}
単純に同じ型の別のイテレータを値初期化します。
編集:std::string
抽出により近い一致が必要な場合は、そうすることもできます:
inline std::istream&
operator>>(std::istream& in, seq& rhs)
{
std::istream::sentry s(in);
if (s)
{
copy_while( std::istreambuf_iterator<char>(in), {},
std::back_inserter(rhs), &is_valid_seq_char);
int eof = std::char_traits<char>::eof();
if (std::char_traits<char>::eq_int_type(in.rdbuf()->sgetc(), eof))
in.setstate(std::ios::eofbit);
}
if (rhs.empty())
in.setstate(std::ios::failbit);
return in;
}
歩哨は先頭の空白をスキップし、入力の最後に到達すると設定されeofbit
ます。おそらく行われるべき他の変更は、何かをそれにプッシュする前に空にすることです。たとえば、あなたのタイプseq
で始まるrhs.clear()
か、同等のものです。seq