为何clang++无法编译clang-tidy推荐的C++20代码?
问题:clang++ 14无法编译含std::ranges::reverse_view的range-based for循环?
问题背景
以下是原版反向迭代循环代码,clang++ 14.0.0可正常编译:
#include <vector> #include <iostream> int main() { auto v = std::vector<unsigned>(); v.push_back(1); v.push_back(2); v.push_back(3); for (auto r = v.rbegin(); r != v.rend(); ++r) { std::cout << *r; } }
clang-tidy 14.0.0建议用C20 ranges改写为以下代码,但clang 14.0.0编译失败(g++ 11.3.0可兼容编译两者),编译参数均为-std=c++20 -Wall -Wextra -Werror:
#include <ranges> #include <iostream> #include <vector> int main() { auto v = std::vector<unsigned>(); v.push_back(1); v.push_back(2); v.push_back(3); for (unsigned int & r : std::ranges::reverse_view(v)) { std::cout << r; } }
根本原因
不是clang的C20支持不足,而是循环变量的类型声明和std::ranges::reverse_view返回的引用类型不匹配:
- 原vector的元素类型是
unsigned,reverse_view包装后,其迭代器解引用返回的是unsigned &类型 - 循环里声明的变量类型是
unsigned int &——尽管unsigned是unsigned int的typedef别名,但在C++模板参数推导中,二者被视为不同的类型(模板匹配是严格的标识符匹配) - clang++ 14对模板参数匹配的检查更严格,因此触发编译错误;而g++ 11.3在这里做了隐式兼容处理,所以能通过编译
修复方法
有两种可行的修复方式:
- 严格匹配引用类型,将循环变量改为
unsigned &:
for (unsigned & r : std::ranges::reverse_view(v)) { std::cout << r; }
- 使用
auto让编译器自动推导正确的引用类型(推荐,避免手动声明类型带来的匹配问题):
for (auto & r : std::ranges::reverse_view(v)) { std::cout << r; }
内容的提问来源于stack exchange,提问作者Krzysiek Karbowiak
相关产品推荐
相关产品推荐

