C++第3版 19章 練習問題解答
目次へ戻る
#include <vector>
#include <iterator>
#include <iostream>
using namespace std;
template <typename T>
void reverse(T i,T j){while (i != j && i != --j) swap(*i++,*j);}
int main()
{
vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3);
ostream_iterator<int> o(cout," ");
reverse(v.begin(),v.end());
copy(v.begin(),v.end(),o);
}
|
VC++ の STL の reverse の実装は、swap の代わりに iter_swap を使っている以外は、
ほぼ同じであった。一応断っておくが、上の解答は VC++ の実装を見ないで作成した。
何もしないということは、UNIX の /dev/null のような存在だと思う。
/dev/null は無用かというとそうではなく、かなり有用である。
Sink の使用方法は以下のような例や、デバッグ時に他の出力反復子と置き換えたりすることが考えられる。
出力反復子の要件については、反復子を参照のこと。
#include <algorithm>
#include <iostream>
using namespace std;
struct Sink {
Sink& operator*(){return *this;}
Sink& operator++(){return *this;}
Sink& operator++(int){return *this;}
template <typename T>
Sink& operator=(const T& t){return *this;}
};
struct TestIter {
int i;
TestIter(int i0 = 0){i = i0;}
TestIter& operator++(){cout << i-- << " "; return *this;}
int operator*(){return i;}
bool operator!=(const TestIter& t){return i != t.i;}
};
int main()
{
TestIter i(10),j;
copy(i,j,Sink());
}
|
この問題は苦労した。VC++ に iterator_traits<T*> が存在しないのである。
すなわち、以下の reverse_iterator は、vector<T>::iterator に対して
使用できない。自前の iterator_traits<T*> を作成しようとしたが、できなかった。
VC++ ではできないような気がする。(非テンプレートならできるが。
18.13参照。)
そこで、deque でテストしている。
ちなみに、VC++ の reverse_iterator は、iterator_traits を使用していない。
さらに、operator+ や operator+= も定義されていなかった。その他の実装は、ほぼ同じであった。
例によって、カンニングはしていない。
iterator_traits の引数を VC++ に合わせて、多少変更してある。
#include <deque>
#include <iostream>
using namespace std;
namespace test {
template <class Iter>
class reverse_iterator : public iterator<iterator_traits<Iter>::iterator_category,
iterator_traits<Iter>::value_type> {
protected:
Iter current;
public:
typedef Iter iterator_type;
typedef iterator_traits<Iter>::distance_type difference_type;
typedef value_type* pointer;
typedef value_type& reference;
reverse_iterator() : current() {}
explicit reverse_iterator(Iter x) : current(x) {}
template <class U>
reverse_iterator(const reverse_iterator<U>& x) : current(x.base()) {}
Iter base()const{return current;}
reference operator*()const{Iter i = current; return *--i;}
pointer operator->()const{Iter i = current; return &*--i;}
reference operator[](difference_type n)const{return *(current-n-1);}
reverse_iterator& operator++(){--current; return *this;}
reverse_iterator operator++(int)
{reverse_iterator r = *this; --current; return r;}
reverse_iterator& operator--(){++current; return *this;}
reverse_iterator operator--(int)
{reverse_iterator r = *this; ++current; return r;}
reverse_iterator operator+(difference_type n)const{return current-n;}
reverse_iterator& operator+=(difference_type n){current -= n; return *this;}
reverse_iterator operator-(difference_type n)const{return current+n;}
reverse_iterator& operator-=(difference_type n){current += n; return *this;}
};
}
int main()
{
deque<int> v;
v.push_back(1); v.push_back(2); v.push_back(3);
test::reverse_iterator<deque<int>::iterator> r(v.end());
cout << r[0] << r[1] << r[2] << endl;
}
|
VC++ の実装を見ると、以下の解答とほぼ同じであった。
#include <string>
#include <iostream>
using namespace std;
namespace test {
template <class T, class Ch = char, class Tr = char_traits<Ch> >
class ostream_iterator : public iterator<output_iterator_tag,void> {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_ostream<Ch,Tr> ostream_type;
ostream_iterator(ostream_type& s) : strm(s) {}
ostream_iterator(ostream_type& s,const Ch* d) : strm(s),deli(d) {}
ostream_iterator& operator=(const T& v){strm << v << deli; return *this;}
ostream_iterator& operator*(){return *this;}
ostream_iterator& operator++(){return *this;}
ostream_iterator& operator++(int){return *this;}
private:
ostream_type strm;
string deli;
};
}
int main()
{
test::ostream_iterator<int> o(cout," ");
*o = 10; *o = 5;
cout << endl;
}
|
これも、時間がかかってしまった。「strm >> t;」でエラーになって
「const basic_istream に operator>> がない」と怒られるのだ。
よくよく見ると、operator>> は、非 const であった。
結局、istream_iterator::operator*() を非 const にしたのが以下の解答である。
#include <iostream>
using namespace std;
namespace test {
template <class T, class Ch = char,
class Tr = char_traits<Ch>, class Dist = ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag,T,Dist> {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_istream<Ch,Tr> istream_type;
istream_iterator(istream_type& s = cin) : strm(s) {}
const T& operator*(){T t; strm >> t; return t;}
const T& operator->(){return operator*();}
istream_iterator& operator++(){return *this;}
istream_iterator& operator++(int){return *this;}
private:
istream_type strm;
};
}
int main()
{
test::istream_iterator<int> i(cin);
int j = *i;
cout << j << endl;
}
|
で、VC++ の実装を見ると、確かに const になっているし、理由も分かった。
直したものを以下に示す。本のコメント(operator* で読込)にだまされた。
#include <iostream>
using namespace std;
namespace test {
template <class T, class Ch = char,
class Tr = char_traits<Ch>, class Dist = ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag,T,Dist> {
public:
typedef Ch char_type;
typedef Tr traits_type;
typedef basic_istream<Ch,Tr> istream_type;
istream_iterator(istream_type& s = cin) : strm(s) {strm >> val;}
const T& operator*()const{return val;}
const T& operator->()const{return operator*();}
istream_iterator& operator++(){strm >> val; return *this;}
istream_iterator& operator++(int){return operator++();}
private:
istream_type strm;
T val;
};
}
int main()
{
test::istream_iterator<int> i(cin);
int j = *i;
cout << j << endl;
}
|
Checked_iter は殆ど完成しているため、足りない部分だけ書く。
尚、operator+ は定義してあるが、2重チェックして無駄であるのであらためて書いた。
valid_rand() { // ランダムアクセス反復子用
if (curr < c->begin() || cur > c->end())
throw out_of_bounds();
}
Checked_iter operator+(Dist d) {
Checked_iter ci += *this;
ci.curr += d;
ci.valid_rand();
return ci;
}
// operator- も同様
bool operator<(const Checked_iter& ci) {
return curr < ci.curr;
}
// operator!= 等も同様
|
全ての関数で valid を呼べばよい。
p648 の Checked が解と思われるので、パス。
パス。
パス。
前章へ
目次へ
次章へ