C++STL容器泛型构造函数的实现 木灵的炼金工作室

在应用STL容器时经常有一个问题:如何方便地将不同容器实例互相转化?

所谓转化,即是以A容器实例中所有元素建立B容器实例:首先我们想到的是双迭代器构造函数T(iterator begin, iterator end),这是一个很好的想法,但是我们希望进一步的语法简化:因此我们使用泛型

template <class other>
vector(const other& _other) noexcept :
    vector(_other.begin(), _other.end()) {}

形如这样的,将双迭代器构造函数以委托构造封装为一个模板类,只要other类型拥有STL容器规定的begin()end()成员函数,我们就可以使用它。

但是这又引发了另外一个问题,即:

不同种容器的begin()end()成员函数返回的迭代器类型不一定是相同的,这就会在某些情况下引发委托构造函数vector(_other.begin(), _other.end())无匹配签名编译错误。

于是我们考虑到,双迭代器构造函数仅仅调用了迭代器的++*重载运算子,所以对于任意拥有这两个运算子的类型,我们都可以使用这个构造函数,而不必拘泥于仅仅适配vector::iterator,类似地,所有被传递调用的函数均需考虑是否需要泛型化。(这是一个解决方案)

template <class inpt_iter>
iterator __alloc_and_copy(inpt_iter begin, inpt_iter end) {
    iterator res = __vector_alloc::allocate(end - begin);
    AMI_std::uninitialized_copy(begin, end, res);
    return res;
}

template <class inpt_iter>
vector(inpt_iter __begin, inpt_iter __end) noexcept {
    size_type __length = __end - __begin;
    __map_begin = __alloc_and_copy(&*__begin, &*__end);
    __map_end = __storage_end = __map_begin + __length;
}

但从另一个角度:我们可以使用”再次引用”操作&*,先对iterator解除引用得到iterator::reference,再对iterator::reference引用得到iterator::pointer,这样将所有的迭代器类型转化为一个原生指针类型,便免去了泛型导致的编码复杂度和编译效率下降。

但是考虑到代码可复用性和可扩展性,选择泛型。

相似地:我认为容器的赋值运算子也可以使用这种技巧,但是这种做法可能会弱化STL对于类型的限制,对于STL初学者来讲有不利之处,但在某些对于数据的处理过程中有着很好的便利性,所以说也不妨实现一下。

需要注意的是,泛型的赋值和copy ctor的优先级要低于确定类型的非模板赋值和copy ctor,而有些编译器会自动生成类的默认赋值和copy ctor,因此需要对于同类赋值/复制重载一份传递调用函数,如

deque(const AMI_std::deque<value_type> &other) noexcept :
    deque(other.begin(), other.end()) {}

这个例子是对于泛型接口的很好的例子。


Copyright AmachiInori 2017-2021. All Right Reserved.
Powered By Jekyll.
amachi.com.cn