【问题标题】:Why can't I reverse a split-range using range-v3?为什么我不能使用 range-v3 反转拆分范围?
【发布时间】:2019-07-18 08:24:53
【问题描述】:

我想使用 range-v3 拆分、反转然后加入一个字符串。但是,下面的代码不会编译。

#include <range/v3/all.hpp>
#include <iostream>

using namespace ranges;

int main(int argc, char *argv[])
{
    auto str = std::string("abc.def.ghi");
    auto sv = str
              | view::split('.')
              | view::reverse
              | view::join('.');
    std::cout<<sv;
    return 0;
}

编译器输出:

error: invalid operands to binary expression ('decltype(pipeable_access::impl<view<reverse_fn> >::pipe(static_cast<ranges::v3::split_view<ranges::v3::iterator_range<std::_String_iterator<std::_String_val<std::_Simple_types<char> > >, std::_String_iterator<std::_String_val<std::_Simple_types<char> > > >, ranges::v3::view::split_fn::element_pred<std::basic_string<char, std::char_traits<char>, std::allocator<char> > &> > &&>(arg), pipe))' (aka 'void') and 'decltype(make_view(view_access::impl<join_fn>::bind(this->view_, static_cast<char &&>(ts))))' (aka 'view<ranges::v3::detail::pipeable_binder<std::_Binder<std::_Unforced, ranges::v3::view::join_fn &, const std::_Ph<1> &, char> > >'))
range\v3\view\any_view.hpp:60: candidate function not viable: cannot convert argument of incomplete type 'decltype(pipeable_access::impl<view<reverse_fn> >::pipe(static_cast<ranges::v3::split_view<ranges::v3::iterator_range<std::_String_iterator<std::_String_val<std::_Simple_types<char> > >, std::_String_iterator<std::_String_val<std::_Simple_types<char> > > >, ranges::v3::view::split_fn::element_pred<std::basic_string<char, std::char_traits<char>, std::allocator<char> > &> > &&>(arg), pipe))' (aka 'void') to 'ranges::v3::category' for 1st argument
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\include\regex:1219: candidate function not viable: cannot convert argument of incomplete type 'decltype(pipeable_access::impl<view<reverse_fn> >::pipe(static_cast<ranges::v3::split_view<ranges::v3::iterator_range<std::_String_iterator<std::_String_val<std::_Simple_types<char> > >, std::_String_iterator<std::_String_val<std::_Simple_types<char> > > >, ranges::v3::view::split_fn::element_pred<std::basic_string<char, std::char_traits<char>, std::allocator<char> > &> > &&>(arg), pipe))' (aka 'void') to 'std::_Node_flags' for 1st argument
range\v3\utility\functional.hpp:725: candidate template ignored: substitution failure [with Arg = void, Pipe = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Binder<std::_Unforced, ranges::v3::view::join_fn &, const std::_Ph<1> &, char> > >, _concept_requires_724 = false, $3 = nullptr]: cannot form a reference to 'void'
range\v3\utility\functional.hpp:734: candidate template ignored: requirement 'false || (is_pipeable<void>() && is_pipeable<ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Binder<std::_Unforced, ranges::v3::view::join_fn &, const std::_Ph<1> &, char> > > >())' was not satisfied [with Pipe0 = void, Pipe1 = ranges::v3::view::view<ranges::v3::detail::pipeable_binder<std::_Binder<std::_Unforced, ranges::v3::view::join_fn &, const std::_Ph<1> &, char> > >, _concept_requires_733 = false]

找到了一种方法:

    auto temp_container = str
              | view::split('.')
              | ::ranges::to_vector
              | action::reverse
              ;
    std::string output = temp_container 
              | view::all
              | view::join('.')
              ;

有更好的想法吗?

【问题讨论】:

  • 很确定他们弄坏了一些东西,因为现在简单的ranges::view::group_by 似乎根本不起作用。我认为问题在于他们可能已经破坏了 范围的范围,但我无法确认。
  • @Fureeish Godbolt 上没有可用的ranges-v3 版本(0.3.00.3.50.3.6trunk)编译此代码 sn-p(在 gccclang)。示例here。但我也不知道当你说“现在”时你在想什么时间范围。
  • @MaxLanghof 谈论 0.5.0 版本。 Godbolt 也不会编译简单的group_bys。鉴于范围仍在开发中,我不想尝试猜测现在出了什么问题。代码应该可以工作。
  • Range-v3 的 view::group_by 测试通过。什么不适合你@Fureeish?
  • 您不能将临时容器通过管道传输到视图适配器中,因为它会创建悬空引用。首先将向量保存到命名变量中。

标签: c++ range-v3


【解决方案1】:

view::split 根据适应的范围返回输入范围或前向范围。 view::reverse 至少需要一个双向范围才能向后迭代。

原则上可以实现一个双向范围的split_view。问题是构造函数已经需要完全遍历适应范围来找到最后一个元素,使其成为 o(n) 操作。据我所知,视图的构造必须是 o(1)。

【讨论】:

  • 感谢您的解释。我认为可能有as_listas_vector之类的东西,所以我们可以在持有视图的o(1)构造时通过管道处理split | as_vector | reverse | join之类的操作。
  • @joyqat:你不能有 O(1) 构造,因为它是一个 vector。构建它必须执行O(n) 副本。所以你不妨将split 的结果粘贴到一个向量中,然后应用reversejoin。为什么要全部放在一条线上?
  • @NicolBolas 因为这样的管道操作可以消除临时性并变得健壮,我认为。此外,如果我可以使用 c++ 做到这一点,那真的很酷。 :P
  • @joyqat 有ranges::to_vectorrange::to&lt;Container&gt; 可以从一个范围内构造一个std::vector 或任意Container。但是你不能像这样通过管道传递它,因为to_vector 返回一个临时向量,它是一个右值,不能通过视图传递。因此,您必须将向量存储为中间结果。这是一件好事,否则它会产生悬空引用。
  • @joyqat:您将如何消除临时性?能够反转它需要首先构建它,因此必须分配内存并复制初始化每个元素。然后,链中的每个后续操作都必须使用生成的容器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2011-12-29
相关资源
最近更新 更多