如何将const_iterator转换为iterator类型迭代器?

前面章节中,已经详细介绍了 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)。