c++gccc++20std-ranges

C++20 ranges - How to store a composed ranges view in class member


How can I store a C++20 ranges composed view as a class member?

I tried with the following code which works with in general, but if I put the struct into a header, GCC warns me that splitter::view has internal linkage. (-Werror=subobject-linkage)

I think GCC is right in this case, but I don't know how to set it to external linkage.

But I think I have a more fundamental problem here, which is I cannot name the type of the range view. In theory I could type that out, but it's a pain if I add another filter to the view.

#include <ranges>
#include <string_view>

#include <fmt/core.h>

struct splitter {
    static constexpr auto split = [](std::string_view command) {
          return command
              | std::views::split(' ')
              | std::views::filter([](auto range) { return !std::ranges::empty(range); })
              | std::views::transform([](auto range) { return std::string_view(range); });
    };

    using ViewType = decltype(split(std::declval<std::string_view>()));

    ViewType view;

    splitter(std::string_view str)
        : view(split(str))
    {
    }
};

int main() {

    std::string_view str = " test foo  bar ";

    splitter sptl(str);
    for (auto s : sptl) {
        fmt::print("token {} with size {}", s, s.size());
    }
}

Here's a godbolt link to the header version: https://godbolt.org/z/avMhqofcf


Solution

  • Issue is that inside the class, class is still incomplete So you have limited access to its internal. changing lambda to regular function, and moving it from the class solve the issue:

    inline constexpr auto split(std::string_view command)
    {
          return command
              | std::views::split(' ')
              | std::views::filter([](auto range) { return !std::ranges::empty(range); })
              | std::views::transform([](auto range) { return std::string_view(range); });
    }
    
    struct splitter {
        using ViewType = decltype(split(std::declval<std::string_view>()));
    
        ViewType view;
    
        splitter(std::string_view str)
            : view(split(str))
        {
        }
    };
    

    Demo