在向量的 std::initializer_list 上调用 std::views::join 时出错

问题描述 投票:0回答:1

我想加入多个视图,而不使用临时变量(如示例中的

arr_and_zeroes
)。但是,这样做会产生编译错误。
有没有什么方法可以不使用临时变量来做到这一点?
我正在使用 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);
  // both of those assignments produce compile-time errors:
  //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

c++ c++20 initializer-list std-ranges
1个回答
0
投票

看来 join 必须传递一个

viewable_range
,其概念概述如下:

template< class T >
concept viewable_range =
    ranges::range<T> &&
    ((ranges::view<std::remove_cvref_t<T>> &&
      std::constructible_from<std::remove_cvref_t<T>, T>) ||
     (!ranges::view<std::remove_cvref_t<T>> &&
      (std::is_lvalue_reference_v<T> ||
       (std::movable<std::remove_reference_t<T>> && !/*is-initializer-list*/<T>))));

参考最后一行,明确不允许初始化列表,除非

std::remove_cvref_t<T>
std::initializer_list
的特化。

您可以查看 cppreference 来查看可行的

viewable_ranges
的示例。

如果您使用的是 C++26,则可以使用

std::ranges::views::concat
代替:

int main() {
    using namespace std::views;
    std::vector<int> arr{2, 3, 7, 5};
    auto cat = concat(single(0), arr, single(0));
}

如果您不使用 C++26,创建临时并使用 join 可能是最简单的解决方案,而无需自己实现 concat。

© www.soinside.com 2019 - 2024. All rights reserved.