C++20编译期检查容器重复元素的实现为何clang编译失败
关于C++20 ranges实现查重函数的编译器兼容问题
C++20之前,实现容器查重功能的一种简单方式是使用嵌套循环,代码如下:
template<typename Container> constexpr bool has_duplicate(Container&& container) { for (auto it1 = container.cbegin(); it1 != container.cend(); ++it1) for(auto it2 = container.cbegin(); it2 != it1; ++it2) if (*it1 == *it2) return 1; return 0; }
随着C++20新增范围for循环初始化语句特性,以及引入了ranges::subrange,我们可以将该函数用范围for循环重写:
template<std::ranges::input_range Container> constexpr bool has_duplicate(Container&& container) { for(auto it = container.cbegin(); const auto& obj1 : container) for(const auto& obj2 : std::ranges::subrange(container.cbegin(), it++)) if(obj1 == obj2) return 1; return 0; }
该实现在GCC上可以正常运行,但在Clang下编译失败,除非手动指定使用libc++,报错信息如下:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/12.0.0/../../../../include/c++/12.0.0/bits/iterator_concepts.h:982:13: error: no matching function for call to '__begin' = decltype(ranges::__cust_access::__begin(std::declval<_Tp&>()));
- 请问是我的实现存在问题,还是clang本身的问题?
我还尝试了另一种实现方式:
template<std::ranges::input_range Container> constexpr bool has_duplicate(Container&& container) { for(auto index = 0ull; const auto& obj1 : container) for(const auto& obj2 : container | std::ranges::views::take(index++)) if(obj1 == obj2) return 1; return 0; }
该实现同样在GCC上无问题,但Clang无论搭配哪款标准库都编译失败。
原因说明
这两个写法都符合C++20标准要求,问题出在编译器和标准库的兼容适配,而非你的实现错误。
- 第一个实现的编译差异是标准库适配问题:GCC自带的libstdc的ranges实现和GCC编译器本身的特性完全适配,所以编译正常。Clang默认使用libstdc时,对libstdc的ranges内部实现的兼容支持不完善,才会出现匹配失败的报错,切换到和Clang配套开发的libc标准库就可以正常编译。
- 第二个实现的全环境Clang编译失败是Clang本身的缺陷:Clang直到16版本才修复了范围for循环结合ranges views使用时的类型推导bug,低于该版本的Clang都无法正常编译这段代码。
兼容修复方案
你可以给模板参数加上std::ranges::common_range约束,避免编译器推导时出现兼容问题,修改后的代码如下:
template<std::ranges::common_range Container> constexpr bool has_duplicate(Container&& container) { for(auto it = container.cbegin(); const auto& obj1 : container) for(const auto& obj2 : std::ranges::subrange(container.cbegin(), it++)) if(obj1 == obj2) return true; return false; }
另外建议返回值直接使用true/false而非1/0,可读性更好。
内容的提问来源于stack exchange,提问作者Ranoiaetep
相关产品推荐
相关产品推荐

