如何將const_iterator轉換為iterator型別疊代器?

2020-07-16 10:05:25
前面章節中,已經詳細介紹了 advance() 和 distance() 函數各自的功能和用法。在此基礎上,本節繼續講解如何利用這 2 個函數實現將 const_iterator 疊代器轉換為 iterator 疊代器,或者將 const_reverse_iterator 疊代器轉換為 reverse_iterator 疊代器。

注意,上面提到的 iterator、const_iterator、reverse_iterator 和 const_reverse_iterator 是 C++ STL 標準庫提供了 4 種基礎疊代器,關於它們各自的特性和功能可以閱讀 《C++ STL疊代器》一節,這裡不再重複贅述。

要知道,C++ STL標準庫為了方便使用者更輕鬆地操作容器,每個容器的模板類都提供有豐富且實用的方法。在這些方法中,有些是以 const_iterator 型別疊代器作為引數,也就意味著在使用此類方法時,需要為其傳入一個 const_iterator 型別的疊代器。

例如,vector 容器模板類中提供有 insert() 方法,該方法的語法格式如下:

iterator insert (const_iterator position, const value_type& val);

注意,此方法有多種語法格式,這裡僅列舉了其中的一種。有關該方法的具體用法,讀者可閱讀《C++ STL vector插入元素》一節,這裡不再做詳細贅述。

可以看到,如果想呼叫此格式的 insert() 方法,就需要為其傳入一個 const_iterator 型別的疊代器。例如:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>value{ 1,2,3,4,5 };
    //定義一個 const_iterator 型別的疊代器
    vector<int>::const_iterator citer = value.cbegin();
    value.insert(citer, 10);
    for (auto iter = value.begin(); iter != value.end(); ++iter) {
        cout << *iter << " ";
    }
    return 0;
}
程式執行結果為:

10 1 2 3 4 5

顯然通過呼叫 insert() 方法,並將指向 value 容器中元素 1 位置處的 const_iterator 型別疊代器作為該方法的實參,就成功將 10 插入到了 value 容器的指定位置。

那麼,是不是給 insert() 方法傳遞其它型別疊代器就不行呢?當然不是,對於給 const_iterator 型別的疊代器傳值,還可以使用 iterator 型別疊代器,但不能使用 const_reverse_iterator 和 reverse_iterator 型別疊代器,這是為什麼呢?

實際上,當我們將某一型別的疊代器傳遞給 insert() 方法中 const_iterator 型別的 position 形參時,即便型別不匹配,編譯器也不會立即報錯,而是先嘗試將其型別轉換成 const_iterator 型別,如果轉換成功,則程式仍可以正常執行;反之如果轉換失敗,編譯器才會報錯。

C++ 中,通常將編譯器自行嘗試進行型別轉換的整個過程稱為隱式轉換(或者自動型別轉換)。

對於 C++ STL 標準庫中的這 4 種基礎疊代器來說,C++ 編譯器的隱式轉換僅支援以下 2 種情況:
  1. 將 iterator 型別的疊代器隱式轉換為 const_iterator 型別的疊代器;
  2. 將 reverse_iterator 型別的疊代器隱式轉換為 const_reverse_iterator 型別的疊代器。

注意,以上 2 種隱式轉換是單向的,即編譯器只支援從 iterator 轉換為 const_iterator,從 reverse_iterator 轉換為 const_reverse_iterator,但不支援逆向轉換。

有些讀者可能會好奇,既然隱式轉換無法做到,還有其他方式可以實現從 const_iterator 到 iterator、從 const_reverse_iterator 到 reverse_iterator 的轉換嗎?

很多讀者可能會想到使用強制型別轉換(const_cast)的方式。但可以明確的是,強制型別轉換並不適用於迭代器,因為 const_cast 的功能僅是去掉某個型別的 const 修飾符,但 const_iterator 和iterator 是完全不同的 2 個類,同樣 const_reverse_iterator 和 reverse_iterator 也是完全不同的 2 個類,它們僅僅是類名有 const 的差別,但並不是 const T 和 T 的關係。

這裡給讀者推薦一種實現方式,就是使用 advance() 和 distance() 這 2 個函數,其語法格式如下:

//將 const_iterator 轉換為 iterator
advance(iter, distance<cont<T>::const_iterator>(iter,citer));
//將 const_reverse_iterator 轉換為 reverse_iterator
advance(iter, distance<cont<T>::const_reverse_iterator>(iter,citer));

其中,citer 為指向某個容器(比如 cont)任意位置的 const_iterator(或者 const_reverse_iterator)型別疊代器,而 iter 通常初始為指向 cont 容器中第一個元素的 iterator(或者 reverse_iterator)型別疊代器。通過套用此格式,最終 iter 會變成一個指向和 citer 一樣的 iterator(或者 reverse_iterator)型別疊代器。

注意,在使用 distance() 函數時,必須額外指明 2 個引數為 const 疊代器型別,否則會因為傳入的 iter 和 citer 型別不一致導致 distance() 函數編譯出錯。

該實現方式的本質是,先建立一個疊代器 citer,並將其初始化為指向容器中第一個元素的位置。在此基礎上,通過計算和目標迭代器 iter 的距離(呼叫 distance()),將其移動至和 iter 同一個位置(呼叫 advance()),由此就可以間接得到一個指向同一位置的 iter 疊代器。

舉個例子:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    vector<int>value{ 1,2,3,4,5 };

    //定義一個 const_iterator 型別的疊代器,其指向最後一個元素
    vector<int>::const_iterator citer = --value.cend();
    //初始化一個非 const 疊代器,另其指向
    vector<int>::iterator iter = value.begin();
    //將 iter 變成和 citer 同樣指向的疊代器
    advance(iter, distance<vector<int>::const_iterator>(iter, citer)); 
    cout <<"*citer = " << *citer << endl;
    cout << "*iter = " << *iter << endl;
    return 0;
}
程式執行結果為:

*citer = 5
*iter = 5

可以看到,通過使用 advance() 和 distance() 函數的組合格式,最終可以得到一個和 citer 指向相同但型別為 iterator 的疊代器。

注意,此方法的實現效率仍取決於目標容器的疊代器型別,如果是隨機存取疊代器,則該方法的執行效率為 O(1);反之,則執行效率為 O(n)。