如何消除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
相关产品推荐
相关产品推荐

