27

STLイテレーターを使用して発生した問題を示すために、最小限の作業例を作成しました。私は:からs(または他のタイプ)istream_iteratorを読み取るために使用しています:floatsstd::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!
}

floatsこれは、EOFが固定サイズの4になるまで、すべての可能なsを読み取りますvalues。したがって、オーバーフローを回避するために範囲を制限し、正確に/最大4つの値を読み取りたいと思います。

より多くの「通常の」イテレータ(つまり、RandomAccessIterator)を使用するbegin+4と、次のように終了しません。

std::copy(begin, begin+4, out);

正確に4つの要素を読み取るため。

これをどのように行うのstd::istream_iteratorですか?明らかなアイデアは、呼び出しを次のように変更するstd::copyことです。

std::copy(std::istream_iterator<float>(std::cin), std::istream_iterator<float>(std::cin)+4, values);

しかし(かなり予想通り)これはコンパイルされません。次の候補はありません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’

助言がありますか?これを達成するための正しい「STLified」pre-C++0xの方法はありますか?もちろん、forループとして書き出すこともできますが、ここでSTLについて何かを学びたいと思っています。std::transformどういうわけかこの機能を実現するために悪用などについて半ば疑問に思ってstd::mergeいましたが、その方法がよくわかりません。

4

3 に答える 3

15

を見てみましょうstd::copy_n 

于 2011-05-10T17:04:42.130 に答える
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;
}

必要に応じて、このジェネレーターをと組み合わせてboost::generator_iterator使用​​して、ジェネレーターを入力イテレーターとして使用できます。

于 2011-05-10T17:28:29.057 に答える
3

利用できるものがない場合はstd::copy_n、独自に作成するのは非常に簡単です。

namespace std_ext { 
template<class InputIterator, class Size, class OutputIterator>
OutputIterator copy_n(InputIterator first, Size n, OutputIterator result) {
    for (int i=0; i<n; i++) {
        *result = *first;
        ++result;
        ++first;
    }
    return result;
}
}
于 2011-05-10T17:19:44.607 に答える