【问题标题】:Ranges-v3 transform limitationsRanges-v3 转换限制
【发布时间】:2022-07-06 17:39:36
【问题描述】:

我正在尝试使用 ranges-v3 将 SNMP OID 拆分为多个部分并将它们作为std::deque<uint32_t> 返回。

以下代码有效,但只有在我添加了一些额外的非自然步骤之后:

#include <range/v3/all.hpp>

/// split the supplied string into nodes, using '.' as a delimiter
/// @param the path to split , e.g "888.1.2.3.4"
/// @return a std::deque<uint32_t> containing the split paths
static std::deque<uint32_t> splitPath(std::string_view path) {
    constexpr std::string_view delim{"."};
    
    auto tmp = path | ranges::views::split(delim)
                | ranges::to<std::vector<std::string>>()
                ;

    return tmp  | ranges::views::transform([](std::string_view v) {
                      return std::stoul(std::string{v}); })
                | ranges::to<std::deque<uint32_t>>();
}

最初我希望以下内容能够简单地工作:

static std::deque<uint32_t> splitPath(std::string_view path) {
    constexpr std::string_view delim{"."};
    
    return path | ranges::views::split(delim)
                | ranges::views::transform([](std::string_view v) {
                      return std::stoul(std::string{v}); })
                | ranges::to<std::deque<uint32_t>>();
}

但这会导致以下错误:

error: no match for ‘operator|’ (operand types are 
‘ranges::split_view<std::basic_string_view<char>, 
 std::basic_string_view<char> >’ and
‘ranges::views::view_closure<ranges::detail::
bind_back_fn_<ranges::views::transform_base_fn, ahk::snmp::
{anonymous}::splitPath(std::string_view)::<lambda(std::string_view)> > >’)

   36 |     return path | ranges::views::split(delim)
      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                 |
      |                 ranges::split_view<std::basic_string_view<char>, 
                         std::basic_string_view<char> >
   37 |                 | ranges::views::transform([](std::string_view v) {
      |                 ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                           |
      |                                           ranges::views::view_closure<ranges::detail::bind_back_fn_
<ranges::views::transform_base_fn, ahk::snmp::
{anonymous}::splitPath(std::string_view)::<lambda(std::string_view)> > >

   38 |                       return std::stoul(std::string{v}); })

为什么在调用ranges::views::transform之前必须将第一个操作的结果转换为std::vector并存储在命名值(tmp)中?即使是以下代码(删除命名值 tmp 也会失败:

static std::deque<uint32_t> splitPath(std::string_view path) {
    constexpr std::string_view delim{"."};
    
    return path | ranges::views::split(delim)
                | ranges::to<std::vector<std::string>>()
                | ranges::views::transform([](std::string_view v) {
                      return std::stoul(std::string{v}); })
                | ranges::to<std::deque<uint32_t>>();
}

【问题讨论】:

    标签: c++ range-v3


    【解决方案1】:

    ranges::views::split返回的范围的值类型不是std::string_view,它是一个实现细节类型。

    我不知道你为什么能| to&lt;std::vector&lt;std::string&gt;&gt;

    因为它使用哨兵,所以您需要将其转换为公共范围(在 C++20 之前,当 std::string_view 可以从迭代器和哨兵构造时,或者在 C++23 之前,当它可以从范围)。

    std::deque<uint32_t> splitPath(std::string_view path) {
        constexpr std::string_view delim{"."};
        
        auto toul = [](auto v){ 
            auto c = v | ranges::views::common; 
            return std::stoul(std::string(c.begin(), c.end())); 
        };
        
        return path | ranges::views::split(delim)
                    | ranges::views::transform(toul)
                    | ranges::to<std::deque<uint32_t>>();
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-24
      • 2021-12-09
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2016-10-13
      • 2021-08-21
      • 1970-01-01
      相关资源
      最近更新 更多