Именованное требование для std :: tuple-like? - PullRequest
0 голосов
/ 09 января 2019

Я делал общий алгоритм хеширования для std::tuple и понял, что могу заставить его работать и для std::pair и std::array, так как эти три класса реализуют std::tuple_size и std::get. Это "стандартизировано" где-нибудь? Есть ли "std::allocator_traits", но для классов, похожих на std :: tuple, вместо классов, похожих на std :: allocator?

В настоящее время я делаю это, чтобы проверить, является ли класс "кортежным":

#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 Ответ

0 голосов
/ 09 января 2019

Это "стандартизировано" где-нибудь?

Если вы имеете в виду алгоритм хеширования, то (как и многие другие) в 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 Это будет воспринято многими как спорное заявление. Тем не менее, это эмпирически верно.

...