You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何消除erase_all_if函数模板两个重载版本的歧义?

消除erase_all_if重载歧义的C++17解决方案

要解决两个erase_all_if版本的重载歧义,核心思路是通过SFINAE机制为两个模板添加迭代器类型约束,让编译器根据容器的迭代器特性自动选择匹配的版本:

方案实现

1. 针对随机访问迭代器容器的版本(如std::vector、std::array)

添加约束,仅当容器的迭代器属于随机访问迭代器范畴时,此版本才会被编译器考虑:

#include <iterator>
#include <type_traits>
#include <algorithm>

template <typename Container, typename Pred>
std::enable_if_t<
    std::is_convertible_v<
        typename std::iterator_traits<typename Container::iterator>::iterator_category,
        std::random_access_iterator_tag
    >,
    typename Container::size_type
>
erase_all_if(Container& c, Pred&& pred)
{
    auto newend = std::remove_if(c.begin(), c.end(), std::forward<Pred>(pred));
    auto ret = c.end() - newend;
    c.erase(newend, c.end());
    return ret;
}

2. 针对非随机访问迭代器容器的版本(如std::list、std::set)

添加反向约束,仅当容器迭代器不属于随机访问范畴时启用此版本:

template <typename Container, typename Pred>
std::enable_if_t<
    !std::is_convertible_v<
        typename std::iterator_traits<typename Container::iterator>::iterator_category,
        std::random_access_iterator_tag
    >,
    typename Container::size_type
>
erase_all_if(Container& c, Pred&& pred) {
    typename Container::size_type removed = 0;
    for (auto it = c.begin(); it != c.end();) {
        if (pred(*it)) {
            it = c.erase(it);
            ++removed;
        }
        else {
            ++it;
        }
    }
    return removed;
}

原理说明

  • std::iterator_traits<typename Container::iterator>::iterator_category用于获取容器迭代器的类型标签
  • std::is_convertible_v判断迭代器标签是否能转换为std::random_access_iterator_tag(兼容C++17新增的contiguous_iterator_tag,比如std::array的迭代器)
  • std::enable_if_t会根据条件的真假决定是否启用当前模板,从而避免两个版本的重载歧义

内容的提问来源于stack exchange,提问作者bobeff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 10:00:18