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