为何无法在std::ranges::transform中直接使用std::get?
为什么直接用std::get在std::ranges::views::transform中编译失败?
你尝试用std::get<0, size_t, size_t>作为std::ranges::views::transform的参数提取pair的第一个元素,代码如下:
std::vector<std::pair<size_t, size_t>> vec { {1, 1}, {2, 7} ,{4, 5}}; for(auto&& x:vec | std::ranges::views::transform(std::get<0, size_t, size_t>)) do_somenthing(x);
但编译报错:
/home/bigbigbige/easytools/transform.cpp: In function ‘int main()’: /home/bigbigbige/easytools/transform.cpp:52:53: error: no match for call to ‘(const std::ranges::views::_Transform) (<unresolved overloaded function type>)’ 52 | for(auto&& x:vec | std::ranges::views::transform(std::get<0, size_t, size_t>)) std::cout << x << std::endl; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
核心原因:std::get的重载歧义
std::get是一个多重重载的模板函数,它不仅支持std::pair,还适配std::tuple、std::array等多种容器类型。当你写出std::get<0, size_t, size_t>时,编译器无法确定你要调用的是哪一个具体重载版本——存在多个符合模板参数的std::get实例,编译器无法将这个重载集转换为transform所需的单一可调用对象类型,最终导致匹配失败。
而你自定义的pair_projection模板函数不存在这个问题:它的模板参数明确绑定了std::pair类型,实例化后是唯一确定的函数,编译器能清晰识别其类型,因此可以正常传递给transform。
更简洁的解决方法
不需要自定义投影函数,有几种更直接的实现方式:
- 使用Lambda表达式(最通用)
Lambda可以明确捕获std::get的调用上下文,消除重载歧义:
std::vector<std::pair<size_t, size_t>> vec { {1, 1}, {2, 7} ,{4, 5}}; for(auto&& x : vec | std::ranges::views::transform([](const auto& p) { return std::get<0>(p); })) { do_somenthing(x); }
- 使用std::views::keys(C++20专属)
C++20标准库提供了std::views::keys视图,专门用于提取std::pair的第一个元素,代码更简洁:
#include <ranges> std::vector<std::pair<size_t, size_t>> vec { {1, 1}, {2, 7} ,{4, 5}}; for(auto&& x : vec | std::views::keys) { do_somenthing(x); }
- 强制类型转换明确重载
通过强制类型转换指定std::get的具体重载版本,告诉编译器你要的是针对std::pair<size_t, size_t>的实例:
std::vector<std::pair<size_t, size_t>> vec { {1, 1}, {2, 7} ,{4, 5}}; using GetFirstFunc = const size_t&(*)(const std::pair<size_t, size_t>&); for(auto&& x : vec | std::ranges::views::transform( static_cast<GetFirstFunc>(std::get<0>) )) { do_somenthing(x); }
内容的提问来源于stack exchange,提问作者葛盈泽
相关产品推荐
相关产品推荐

