调用std::views::join处理vector初始化列表的编译错误及无临时变量实现问询
问题
我想不用临时变量(比如示例里的arr_and_zeroes)调用std::views::join合并多个视图,但直接这么写会编译报错。请问有没有不需要临时变量的实现方式?我用的是g++ 14.2.1编译器。
代码示例
#include <vector> #include <ranges> #include <type_traits> int main() { std::vector<int> arr{2, 3, 7, 5}; auto arr_and_zeroes = {{0}, arr, {0}}; static_assert(std::is_same_v< decltype(arr_and_zeroes), std::initializer_list<std::vector<int>> >); auto r1 = std::views::join(arr_and_zeroes); // 以下两行赋值均会产生编译错误: //auto r2 = std::views::join({{0}, arr, {0}}); //auto r3 = std::views::join( // std::initializer_list<std::vector<int>>{{0}, arr, {0}} //); }
编译错误信息
r2赋值的错误信息
bug2.cpp: In function ‘int main()’: bug2.cpp:15:29: error: no match for call to ‘(const std::ranges::views::_Join) (<brace-enclosed initializer list>)’ 15 | auto r2 = std::views::join({{0}, arr, {0}}); | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~ In file included from bug2.cpp:2: /usr/include/c++/14.2.1/ranges:3227:9: note: candidate: ‘template<class _Range> requires (viewable_range<_Range>) && (__can_join_view<_Range>) constexpr auto std::ranges::views::_Join::operator()(_Range&&) const’ 3227 | operator() [[nodiscard]] (_Range&& __r) const | ^~~~~~~~ /usr/include/c++/14.2.1/ranges:3227:9: note: template argument deduction/substitution failed: bug2.cpp:15:29: note: couldn’t deduce template parameter ‘_Range’ 15 | auto r2 = std::views::join({{0}, arr, {0}}); | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
r3赋值的错误信息
bug2.cpp: In function ‘int main()’: bug2.cpp:16:29: error: no match for call to ‘(const std::ranges::views::_Join) (std::initializer_list<std::vector<int> >)’ 16 | auto r3 = std::views::join( | ~~~~~~~~~~~~~~~~^ 17 | std::initializer_list<std::vector<int>>{{0}, arr, {0}} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | ); | ~ In file included from bug2.cpp:2: /usr/include/c++/14.2.1/ranges:3227:9: note: candidate: ‘template<class _Range> requires (viewable_range<_Range>) && (__can_join_view<_Range>) constexpr auto std::ranges::views::_Join::operator()(_Range&&) const’ 3227 | operator() [[nodiscard]] (_Range&& __r) const | ^~~~~~~~ /usr/include/c++/14.2.1/ranges:3227:9: note: template argument deduction/substitution failed: /usr/include/c++/14.2.1/ranges:3227:9: note: constraints not satisfied In file included from /usr/include/c++/14.2.1/bits/ranges_util.h:34, from /usr/include/c++/14.2.1/tuple:44, from /usr/include/c++/14.2.1/bits/uses_allocator_args.h:39, from /usr/include/c++/14.2.1/bits/memory_resource.h:41, from /usr/include/c++/14.2.1/vector:87, from bug2.cpp:1: bug2.cpp: In substitution of ‘template<class _Range> requires (viewable_range<_Range>) && (__can_join_view<_Range>) constexpr auto std::ranges::views::_Join::operator()(_Range&&) const [with _Range = std::initializer_list<std::vector<int> >]’: bug2.cpp:16:29: required from here 16 | auto r3 = std::views::join( | ~~~~~~~~~~~~~~~~^ 17 | std::initializer_list<std::vector<int>>{{0}, arr, {0}} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | ); | ~ /usr/include/c++/14.2.1/bits/ranges_base.h:808:13: required for the satisfaction of ‘viewable_range<_Range>’ [with _Range = std::initializer_list<std::vector<int, std::allocator<int> > >] /usr/include/c++/14.2.1/bits/ranges_base.h:810:11: note: no operand of the disjunction is satisfied 809 | && ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>, _Tp>) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 810 | || (!view<remove_cvref_t<_Tp>> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 811 | && (is_lvalue_reference_v<_Tp> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 812 | || (movable<remove_reference_t<_Tp>> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 813 | && !__detail::__is_initializer_list<remove_cvref_t<_Tp>>)))); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1plus: note: set ‘-fconcepts-diagnostics-depth=’ to at least 2 for more detail
解决方案
先说明原写法失败的原因:
r2写法:编译器无法从无类型的花括号列表推导_Range模板参数。r3写法:std::initializer_list不满足viewable_range约束——该约束要求范围要么是视图且可构造,要么不是视图但满足「是左值引用」或「是可移动类型且不是initializer_list」,而initializer_list正好命中排除项。
以下是几种无需临时变量的可行实现:
方法1:用std::views::concat+join串联视图
std::views::concat可以接受多个范围并返回合法视图,满足viewable_range要求,适合直接传给join:
auto r4 = std::views::concat(std::views::single(0), arr, std::views::single(0)) | std::views::join;
这里用std::views::single(0)创建单个元素的视图,避免临时vector的开销,同时保证类型合法。
方法2:用std::array包裹子范围
std::array满足viewable_range约束,可以直接作为join的参数:
auto r5 = std::views::join(std::array{std::vector{0}, arr, std::vector{0}});
注意所有子元素类型需统一(此处都是std::vector<int>),编译器会自动推导std::array的模板参数。
方法3:用生成器视图构造(适合固定元素场景)
如果只是在前后添加固定值,可通过transform生成对应范围的引用,再join:
auto r6 = std::views::iota(0, 3) | std::views::transform([&](int i) -> auto& { static std::vector<int> zero{0}; return (i == 0 || i == 2) ? zero : arr; }) | std::views::join;
这种方式避免了多个临时vector的创建,注意静态变量的生命周期仅适用于简单场景。
内容的提问来源于stack exchange,提问作者Pootis Spencer
相关产品推荐
相关产品推荐

