Именованное требование для std::tuple-like?
Я делал общий алгоритм хеширования для std::tuple
и понял, что смогу заставить его работать на std::pair
а также std::array
а также, как эти три класса реализуют std::tuple_size
а также std::get
, Это "стандартизировано" где-нибудь? Есть ли "std::allocator_traits
"но для std::tuple-подобных классов вместо std::allocator-like классов?
В настоящее время я делаю это, чтобы проверить, является ли класс "кортежным":
#include <type_traits>
#include <cstddef>
#include <utility>
#include <tuple>
namespace is_tuple {
namespace detail {
// T* exists for incomplete types, but not sizeof(T)
template<class T, ::std::size_t = sizeof(T)>
::std::true_type is_complete_type_impl(T*);
::std::false_type is_complete_type_impl(...);
template<class T>
struct is_complete_type : decltype(
is_complete_type_impl(::std::declval<T*>())
) {};
}
template<class T>
struct is_tuple : detail::is_complete_type<::std::tuple_size<T>>::type {};
}
Это может иметь некоторые ложные срабатывания (хотя я не думаю, что это так)
Это "требования", которые я навязываю для "кортежоподобных" типов, для типа T
и объект типа T
называется t
:
std::tuple_size<T>
это полный типstd::tuple_size<T>::value
этоstatic constexpr const std::size_t
(называетсяN
)std::get<I>(t)
возвращает не пустые для всехI
в [0
,N
)
(Это правильно и полно? Я также реализовал проверку std::get
, но код был слишком длинным для публикации)
А также, есть ли лучший способ указать, является ли тип "кортежоподобным", кроме специализации std::tuple_size<T>
(Может быть что-то вроде iterator_tag)
1 ответ
Это "стандартизировано" где-нибудь?
Если вы имеете в виду алгоритм хеширования, то (как и многие другие) уже есть полное решение в boost
,
boost
конечно, возможно, более стандартизирован и, безусловно, более переносим, чем различные реализации самого стандарта C++.1
#include <boost/functional/hash.hpp>
#include <tuple>
#include <utility>
#include <array>
#include <string>
#include <iostream>
template<class T>
std::size_t hashit(T const& x)
{
using x_type = std::decay_t<T>;
return boost::hash<x_type>()(x);
}
template<class T>
std::size_t hashit2(T const& x)
{
using boost::hash_value;
return hash_value(x);
}
int main()
{
using namespace std::literals;
std::cout << hashit(std::make_tuple(1, 2, 5, "foo"s)) << '\n';
std::cout << hashit2(std::make_tuple(1, 2, 5, "foo"s)) << '\n';
std::cout << '\n';
std::cout << hashit(std::make_pair(1.0, 2.0)) << '\n';
std::cout << hashit2(std::make_pair(1.0, 2.0)) << '\n';
std::cout << '\n';
std::cout << hashit(std::array<int, 3>{4, 5, 6}) << '\n';
std::cout << hashit2(std::array<int, 3>{4, 5, 6}) << '\n';
}
1 Это будет воспринято многими как спорное заявление. Тем не менее, это эмпирически верно.