mercredi 1 septembre 2021

is there an easy way to determine whether a type is "span-like"?

It seemingly takes a fair amount of what looks to be boilerplate code to determine whether a T is std::span-like, that is does it have T().data() and T().size().

First, I have an exists utility:

template <typename T, template <typename...> typename Test>
struct exists final
{
    template<typename U>
    static constexpr std::true_type check(Test<U>*);

    template<typename U>
    static constexpr std::false_type check(...);

    static constexpr bool value = decltype(check<T>(0))::value;
};

Then a test utility for .data() and another one for .size():

template<typename T, typename = decltype(std::declval<T>().data())> struct data_test final {};
template<typename T, typename = decltype(std::declval<T>().size())> struct size_test final {};

And finally the test itself:

template<typename T>
struct is_spanlike final : std::integral_constant<
    bool, exists<T, data_test>::value && exists<T, size_test>::value> {};

This works fine with std::enable_if:

template <typename T,
    typename std::enable_if<!is_spanlike<T>::value, bool>::type = true>
    void h(const T& t)
{
    std::clog << "'POD'?\n";
    const void* data = &t;
    const size_t size = sizeof(t);
}
template <typename T,
    typename std::enable_if<is_spanlike<T>::value, bool>::type = true>
    void h(const T& t)
{
    std::clog << "span-like\n";
    const void* data = t.data();
    const size_t size = t.size() * sizeof(T);
}

std::vector<int> v;
h(v);
h(314);

but, again, it seems like an awful lot of boilerplate.

Is there an easier (i.e., less of my own code) way to write is_spanlike? (Without using C++20.)

Aucun commentaire:

Enregistrer un commentaire