Search code examples
c++c++20

Check if parameter pack contains a std::span<U>


I am iterating over an argument sequence at compile-time, and I want to check if one of the arguments may be a span. If so, I will do span-things.

    template<typename... Args, std::size_t... Indices>
    inline auto SomeClass::resolve_args(std::index_sequence<Indices...>) const
    {
        std::tuple<std::decay_t<Args>...> retval;
        size_t i = 0;
        size_t f = 0;
        ([&] {
            if constexpr (std::is_integral_v<Args>) {
                std::get<Indices>(retval) = sysarg<Args>(i++);
            }
            else if constexpr (std::is_floating_point_v<Args>)
                std::get<Indices>(retval) = sysarg<Args>(f++);
            else if constexpr (std::is_same_v<Args, std::basic_string_view<char>>) {
                std::get<Indices>(retval) = sysarg<Args>(i); i+= 2;
            }
            else if constexpr (is_stdstring<Args>::value)
                std::get<Indices>(retval) = sysarg<Args>(i++);
            else if constexpr (std::is_standard_layout_v<remove_cvref<Args>> && std::is_trivial_v<remove_cvref<Args>>)
                std::get<Indices>(retval) = sysarg<Args>(i++);
            else
                static_assert(always_false<Args>, "Unknown type");
        }(), ...);
        return retval;
    }

Somewhere in there I need to check if Args is a Span. Is that possible? My problem so far is that my attempts at an if constexpr branch makes other type-combinations fail. So, I am posting the whole function (with minor modifications). You can implement sysarg as a do-nothing function.

Ideally, the spans subtype would be trivial and standard_layout, but I can handle the details. I just need to figure out how to proceed!


Solution

  • #include <span>
    #include <type_traits>
    
    template <typename T>
    struct is_span : std::false_type{};
    template <typename T>
    struct is_span<std::span<T>> : std::true_type{};
    template <typename T>
    constexpr bool is_span_v = is_span<T>::value;
    
    int main() {
        static_assert(is_span_v<std::span<int>>);
        static_assert(!is_span_v<int>);
    }
    

    Edit:

    The above only works for spans with dynamic extent. To make it work on all spans change the is_span specialization to this:

    template <typename T, std::size_t Extent>
    struct is_span<std::span<T, Extent>> : std::true_type{};
    

    live example