Deferrenced指向散列编译时字符串的指针

时间:2018-03-10 22:54:20

标签: c++ string hash metaprogramming std-pair

我试图实现某种使用编译时字符串作为键(该对的第一个元素)的映射(一对元组)。所以我想使用这个answer,但是我的代码存在问题:字符串在一对内。

#include <type_traits>
#include <tuple>

namespace meta {

    template < typename T >
    struct CType { using type = T; };


  namespace detail {
    template <typename T>
    struct typeid_t {
      using type = typename std::remove_cv<
        typename std::remove_reference<T>::type
      >::type;
    };
  }

  template <typename T>
  constexpr decltype(auto) typeid_(T&&) {

    return CType<typename detail::typeid_t<T>::type>{};
  }
}


  struct  HashConstString {

    using value_type = uint32_t;

    static constexpr uint32_t hash(const char* str) {
        return str[0];
    }
  };


template < typename T_Hash,
           typename... T_Pairs >

  class  UniversalMap {

        template < typename T_Pair >
        using U_Pair = decltype(std::make_pair(
          std::integral_constant<typename T_Hash::value_type, T_Hash::hash(std::get<0>(T_Pair{}))>{},
          typename decltype(meta::typeid_(std::get<1>(T_Pair{})))::type {}
        ));

      using U_Map = decltype(std::make_tuple(
        U_Pair<T_Pairs>{}...
      ));

      private:
        U_Map        m_map;
  };

template < typename T_Hash,
           typename... T_Pairs >
    constexpr decltype(auto)  make_UniversalMap(T_Hash hash, T_Pairs... pairs) {

    (void)hash;
    ((void)pairs,...);
    return UniversalMap<T_Hash, T_Pairs...>();
}

int main() {

    constexpr auto hashValue = HashConstString::hash("Test");
    constexpr auto map = make_UniversalMap(HashConstString{},
      std::make_pair("Test", meta::CType<int>{})
    );
}

Wandbox

所以我不知道当字符串已经在字符串中时如何正确地散列字符串。因为std :: get给了我一个引用,这似乎是我有一个解除引用的空指针错误的原因。

是否有一些&#34;技巧&#34;在创建配对之前不必计算哈希就可以完成这项工作吗?

1 个答案:

答案 0 :(得分:1)

问题不在于std::get,而在于您创建了const char*的元组。当"Test"作为参数传递给const char*时,make_pair会衰减到std::pair<const char[5], int>。不幸的是,显式指定对模板参数(例如std::array)不起作用,因为您无法创建类型为array的std容器。

相当尴尬的解决方案是使用struct HashConstString { using value_type = uint32_t; static constexpr uint32_t hash(const char *str) { return str[0]; } // add this overload template <std::size_t N> static constexpr uint32_t hash(std::array<char, N> str) { return str[0]; } };

constexpr auto map = make_UniversalMap(HashConstString{},
                         std::make_pair(std::array<char, 5>{"Test"}, int{}));

然后像这样打电话:

std::array

为避免指定template <std::size_t N> constexpr auto make_strarray(const char(&str)[N]) { // unfortunately std::array<char, N>{str} does not work :( std::array<char, N> arr{}; for (std::size_t i = 0; i < N; ++i) arr[i] = str[i]; return arr; } 的大小,您可以创建辅助函数:

C++20

或者在std::copy template <std::size_t N> constexpr auto make_strarray(const char(&str)[N]) { std::array<char, N> arr{}; std::copy(str, str + N, arr.begin()); return arr; } 看起来brew uninstall --ignore-dependencies --force python python@2 unset PYTHONPATH brew install python python@2 将成为constexpr:

pip