Именованное требование для 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:

  1. std::tuple_size<T> это полный тип
  2. std::tuple_size<T>::value это static constexpr const std::size_t (называется N)
  3. 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 Это будет воспринято многими как спорное заявление. Тем не менее, это эмпирически верно.

Другие вопросы по тегам