Qt:为模板(映射、列表、集合等)构建一个可变迭代器

Qt: construct a mutable iterator for template (maps, lists, sets, ...)

本文关键字:构建 一个 迭代器 集合 映射 Qt 列表      更新时间:2023-10-16

在我的代码中,我经常让函数在不同的可迭代Qt容器类型上做同样的事情,例如:

void removeX(QMap<qint64, QString> & map)
{
    QMutableMapIterator<qint64, QString> it(map);
    while (it.hasNext()) {
        it.next();
        if (it.value() == "X") it.remove();
    }
}
void removeX(QList<QString> & list)
{
    QMutableListIterator<QString> it(list);
    while (it.hasNext()) {
        it.next();
        if (it.value() == "X") it.remove();
    }
}

(我知道 QList 中已经有一个removeAll函数。这只是一个愚蠢的最小示例)

实际代码更复杂,因此引入了大量代码重复。我宁愿有这样的东西:

template <typename T>
void removeX_(T & container)
{
    typename T::mutable_iterator it(container);
    while (it.hasNext()) {
        it.next();
        if (it.value() == "X") it.remove();
    }
}

当然,这不能编译,因为Qt中根本没有"::mutable_iterator"类型定义。我看不出一个简单的方法。像"template<...>getMyMutableIterator"这样的函数在这种情况下不起作用,因为我们不允许为重载的函数返回不同的类型。

但是 C++17 中有很多新的"模板魔法",我还没有真正理解。我可以想象这可能是实现上述代码的简单方法。有没有人可以减少这里的代码重复的解决方案?

您可以定义特征模板,并部分专注于适当的容器

template <typename Container> struct q_container_traits;
template <typename T> struct q_container_traits<QList<T>>
{
    using mutable_iterator = QMutableListIterator<T>;
    using const_iterator = QListIterator<T>;
};
template <typename Key, typename Value> struct q_container_traits<QMap<Key, Value>>
{
    using mutable_iterator = QMutableMapIterator<Key, Value>;
    using const_iterator = QMapIterator<Key, Value>;
};
// etc

然后,在函数中使用q_container_traits<T>

template <typename T>
void removeX(T & container)
{
    typename q_container_traits<T>::mutable_iterator it(container);
    while (it.hasNext()) {
        it.next();
        if (it.value() == "X") it.remove();
    }
}
您可以使用

SFINAE 禁用那些没有mutable_iterator类型的参数T的函数模板,使用 std::enable_if_tstd::is_same

template <typename T>
std::enable_if_t
<
    std::is_same_v
    <
        typename T::mutable_iterator, 
        mutable_iterator
    >, 
    void
> 
removeX_(T & container)
{
    typename T::mutable_iterator it(container);
    while (it.hasNext()) {
        it.next();
        if (it.value() == "X") it.remove();
    }
}

其内容如下:如果类型与 mutable_iterator 相同,则启用 void 类型作为函数的返回类型T::mutable_iterator 。如果 T 没有mutable_iterator,则替换失败。

您可以使用type_traits使其适应T或其迭代器上的其他条件,例如检查它是否具有remove()成员函数。