C++ STL Iterator Adaptor

STL Iterator Adaptor

讓操作物件行為彷彿像在操作 Iterator 一樣,使用 Iterator Adaptor 來包裝你物件的 特殊行為,讓外界以為是一個 iterator。

讓 STL 演算法間接操作容器獨有的操作

由於 STL 演算法,只會依照 Iterator 的行為支援,來對傳入的 Iterator 做操作。它不認得 push_backpush_froninsertoperator>>operator<< 等等這種 與物件相依的操作。所以你需要某種 Adaptor 來將一些 與物件相依的操作 包裝成 STL Algorithm 認得的 Iterator 操作。

以下依照常用到的順序,介紹 STL 所提供的幾種 Adaptor,用來包裝 STL 容器、或是 STL Stream:

包裝 push_back

操作 container::push_back(element); 仿彿在操作 *i++ = element;

容器獨有的 push_back 操作
string source[3] = {str1, str2, str3};
vector<string> vec;
for(auto i = source; i != source+3; i++)
    vec.push_back(*i);
`*i++ = element` 的等價操作
auto vec_adaptor = back_inserter(vec);
for(auto i = source; i != source+3; i++)
    *vec_adaptor++ = *i;
  • vec_adaptor++ 沒做事
  • *vec_adaptor 沒做事
  • vec_adaptor = str3 做了 vec.push_back(str3);
  • 就算 operator++ 與 operator* 沒做事,寫成這樣的目的是為了模仿 STL Algorithm 內部的操作
使用 STL Algorithm 的等價操作
copy(source, source+3, vec_daptor);

cppreference.com 所說的 copy 可能作法

http://en.cppreference.com/w/cpp/algorithm/copy

template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, 
              OutputIt d_first)
{
    while (first != last) {
        *d_first++ = *first++;
    }
    return d_first;
}

可以看到它對於 outputIterator 會是使用 *d_first++ = element 的操作

包裝 operator<<

操作 ostream << element 仿彿在操作 *i++ = element

ostream 的 operator《《: 印出陣列內的值。
string source[3] = {str1, str2, str3};
for(auto i = source; i != source+3; i++)
    cout << *i;
模仿 Iterator `*i++ = element` 的等價操作
ostream_iterator<string> cout_adaptor(cout, "");
for(auto i = source; i != source+3; i++)
    *cout_adaptor++ = *i;
  • cout_adaptor++ 沒做事
  • *cout_adaptor 沒做事
  • cout_adaptor = source[i]; 做了 cout << source[i]; 的事
使用 STL Algorithm 的等價操作
copy(source, source+3, cout_adaptor);

包裝 operator>>

操作 istream >> element; 仿彿在操作 element = *i++;

cin 的 operator》》:並持續讀取標準(鍵盤)輸入,直到讀取到 EOF (Ctrl + D)
vector<string> vec;
while(cin >> str)
  vec.push_back(str);
模仿 Iterator `element = *i++` 與 test `i != end_of_iterator` 的等價操作
istream_iterator<string> cin_adaptor(cin), cin_adaptor_end;
for(auto i = cin_adaptor; i != cin_adaptor_end; i++)
  vec.push_back(*i);
  • i != end_iterator 做了判斷是否結束
  • i++ 做了步進
  • *i 做了提領。
  • 這些都是 STL Iterator 中最低標準的 InputIterator 所支援的操作

istream_iterator 的 end 哨兵

由於一般在操作 cin 的時候,是去判斷是否遇上了 EOF 來常做是一個結束。那麼在 istream_iterator 的 EOF 符號, end iterator,就是定出一個依照不帶任何參數 default constructor 初始化的同型 istream_iterator。

使用 STL Algorithm 的等價操作
copy(cin_adaptor, end_of_iterator, back_inserter(vec));

包裝 insert

操作 container::insert(insert_position, element 仿彿在操作 *i++ = element

vector 的 insert: 將 str3 ~ str5 插在 str2 與 str6 之間
string source[3] = {str3, str4, str5};
vector<string> vec = {str1, str2, str6};
for(auto i = source; i!= source + 3; i++)
  vec.insert(vec.begin() + 2, *i);
模仿 Iterator *i++ = element 的等價操作
auto vec_adaptor = inserter(vec, vec.begin() + 2);
for(auto i = source; i != source + 3; i++)
    *vec_adaptor++ = *i;
  • inserter 會回傳一個 insert_iterator<vector<string>>(vec, vec.begin() + 2) 的物件
  • *vec_adaptor 沒做事
  • vec_adaptor++ 沒做事
  • 只有 vec_adaptor.operator=(*i) 真正做了 insert 的操作。
使用 STL Algorithm 的等價操作
copy(source, source + 3, vec_adaptor);
comments powered by Disqus