Search code examples
c++c++20c++-conceptsc++-templates

How does one constrain a template function to a range of templated types?


I have a type that is a template type, and a vector of said type

template<typename T>
struct result_t { 
    T value;
};

template<typename elem_type>
using list_t = std::vector<result_t<elem_type>>;

How do I define I generic function that is constrained to such a range?

Hard coded with just a vector:

template<typename elem_type>
auto values(const std::vector<result_t<elem_type>>& values) {...}

I would like to update my function to be generic, to take any type of range, even a view

template<typename range_t>
concept is_result_range = std::ranges::range<range_t> && ...;

template<is_result_range range_t>
auto values(const range_t& values) {...}

I have tried:

template<typename range_t, typename element_t>
concept is_result_range = std::ranges::range<range_t>
    && std::is_same_v<typename std::ranges::range_value_t<range_t>, result<element_t>>;

But the compiler is not happy since it can't deduce the template arguments.


Solution

  • You can use template specialization to detect that the value type of range is a specialization of result_t

    #include <ranges>
    
    template<typename T>
    struct result_t { 
      T value;
    };
    
    template<typename T>
    constexpr bool is_result_t = false;
    template<typename T>
    constexpr bool is_result_t<result_t<T>> = true;
    
    template<typename range_t>
    concept is_result_range = std::ranges::input_range<range_t>
        && is_result_t<std::ranges::range_value_t<range_t>>;
    

    Then you can constrain the function as

    template<is_result_range R>
    auto values(R&& values) {
      return values
           | std::views::transform([](const auto& res) { return res.value; });
    }