为何GCC与Clang无法优化枚举类型的vector与array比较?
枚举类型与
std::ranges::equal的优化差异问题 我在审查一段检查std::unordered_set是否仅包含某个特定枚举值的代码时,原实现逻辑如下:
if (values.size() == 1 && *values.cbegin() == FOO) { // 核心业务逻辑 }
为了提升可读性,我建议改用std::ranges::equal实现,代码如下:
if (std::ranges::equal(values, std::array{FOO})) { // 核心业务逻辑 }
这种写法可读性更优,但理论上效率略低于原版本(多一次大小判断)。不过针对std::unordered_set的测试显示,两者的汇编代码差异不大。完整测试代码如下:
#include <algorithm> #include <array> #include <ranges> #include <unordered_set> enum class Foo { A, B, C }; auto is_b_v1(const std::unordered_set<Foo> &v) { return v.size() == 1 && *v.cbegin() == Foo::B; } auto is_b_v2(const std::unordered_set<Foo> &v) { return std::ranges::equal(v, std::array{Foo::B}); }
但将容器替换为std::vector后,std::ranges::equal版本的汇编代码效率明显更低:
手动判断版本(v1)汇编
is_b_v1(std::vector<Foo, std::allocator<Foo> > const&): mov rcx, QWORD PTR [rdi] mov rax, QWORD PTR [rdi+8] xor edx, edx sub rax, rcx cmp rax, 4 jne .L1 cmp DWORD PTR [rcx], 1 sete dl .L1: mov eax, edx ret
std::ranges::equal版本(v2)汇编
is_b_v2(std::vector<Foo, std::allocator<Foo> > const&): mov rcx, QWORD PTR [rdi+8] mov rax, QWORD PTR [rdi] mov DWORD PTR [rsp-4], 1 xor edx, edx mov rsi, rcx sub rsi, rax cmp rsi, 4 jne .L5 cmp rcx, rax je .L9 lea rdx, [rsp-4] jmp .L7 .L12: add rax, 4 add rdx, 4 cmp rcx, rax je .L9 .L7: mov esi, DWORD PTR [rdx] cmp DWORD PTR [rax], esi je .L12 xor edx, edx .L5: mov eax, edx ret .L9: mov edx, 1 mov eax, edx ret
而当把枚举类型替换为int后,两种写法的汇编代码完全一致。该现象在GCC与Clang中均存在,请问为何编译器无法像优化int类型那样优化枚举类型的vector与array比较?
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

