如何声明可直接用于range-v3的ranges::views::transform的范围输入函数
问题
我想声明一个以range为输入、返回单个数值的函数,让它能直接用于range-v3库的ranges::views::transform视图。目前通过无实际逻辑的lambda包裹函数调用可以运行,但我希望去掉lambda,直接把函数传入transform。请问能不能通过修改getGroupValue的参数类型实现,还是必须用lambda?
现有可运行代码
int64_t getGroupValue( ranges::input_range auto&& group ) { return ranges::accumulate( group, 1ll, ranges::multiplies() ); } int64_t calculateGroupSum( const std::vector<int>& data ) { using ranges::views::transform; using ranges::views::chunk; return ranges::accumulate( data | chunk( 3 ) | transform( [] ( auto group ) { return getGroupValue( group ); }) , 0ll); }
期望实现的代码
int64_t calculateGroupSum( const std::vector<int>& data ) { using ranges::views::transform; using ranges::views::chunk; return ranges::accumulate( data | chunk( 3 ) | transform( getGroupValue ) , 0ll); }
解决方案
可以通过修改getGroupValue的参数类型实现,完全不需要lambda。
问题根源在于原函数的参数ranges::input_range auto&&,当直接传递函数名给transform时,模板参数推导会出现不匹配的情况——transform期望的可调用对象需要能接收chunk(3)生成的具体右值范围类型,而auto&&作为函数参数的推导规则无法满足这一要求。
修改后的getGroupValue(两种可选写法)
写法一:显式模板化范围类型(C++20及以上)
template <ranges::input_range Range> int64_t getGroupValue(Range&& group) { return ranges::accumulate(std::forward<Range>(group), 1ll, ranges::multiplies()); }
写法二:按值接收范围(更简洁)
int64_t getGroupValue(ranges::input_range auto group) { return ranges::accumulate(group, 1ll, ranges::multiplies()); }
原理说明
把参数从auto&&改为按值接收,或者显式模板化范围类型后,函数的类型推导逻辑会和transform的需求完全匹配,此时直接传递getGroupValue函数名给transform就能正常工作,无需再用lambda包裹。
修改后,你期望的calculateGroupSum代码可以直接运行,和你给出的示例完全一致。
内容的提问来源于stack exchange,提问作者Grimkin
相关产品推荐
相关产品推荐

