You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:59:54