【问题标题】:Simple C++11 hash function won't compile简单的 C++11 哈希函数无法编译
【发布时间】:2019-10-22 07:13:47
【问题描述】:

以下简单哈希函数的代码无法编译

#include <cstddef>
#include <functional>

namespace {
    struct Foo {
        long i;
    };
}

namespace std {
    template<> struct hash<::Foo> {
        size_t operator()(::Foo foo) const {
            return hash<decltype(foo.i)>(foo.i);
        }
    };
}

我的 4.8.5 g++ 编译器发出这些消息:

$ g++ -std=c++11 a.cpp
a.cpp: In member function ‘std::size_t std::hash<{anonymous}::Foo>::operator()({anonymous}::Foo) const’:
a.cpp:13:47: error: no matching function for call to ‘std::hash<long int>::hash(long int&)’
             return hash<decltype(foo.i)>(foo.i);
                                               ^
a.cpp:13:47: note: candidates are:
In file included from /usr/include/c++/4.8.2/bits/basic_string.h:3033:0,
                 from /usr/include/c++/4.8.2/string:52,
                 from /usr/include/c++/4.8.2/stdexcept:39,
                 from /usr/include/c++/4.8.2/array:38,
                 from /usr/include/c++/4.8.2/tuple:39,
                 from /usr/include/c++/4.8.2/functional:55,
                 from a.cpp:2:
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash()
   _Cxx_hashtable_define_trivial_hash(long)
   ^
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note:   candidate expects 0 arguments, 1 provided
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash(const std::hash<long int>&)
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note:   no known conversion for argument 1 from ‘long int’ to ‘const std::hash<long int>&’
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note: constexpr std::hash<long int>::hash(std::hash<long int>&&)
/usr/include/c++/4.8.2/bits/functional_hash.h:107:3: note:   no known conversion for argument 1 from ‘long int’ to ‘std::hash<long int>&&’
$ fg

问题似乎是第一条错误消息中的引用调用,但我不明白为什么或如何解决它。

【问题讨论】:

  • 仅供参考,namespace std {}; 调用未定义的行为。你不应该扩展命名空间标准。
  • @Chipster 不完全是。 “只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且未明确禁止时,程序才能将任何标准库模板的模板特化添加到 namespace std。”
  • @Chipster 在这种情况下是合法的。您可以打开命名空间并为您的类型添加专业化。见:timsong-cpp.github.io/cppwp/n4659/namespace.std#1
  • @Brian,但添加其他内容是未定义的行为,除了模板。
  • @Chipster 但是 OP 正在做的正是合法的事情:为他们自己的类型添加一个标准模板的专业化。这是将您的类型与std::hash 网格化的方法。

标签: c++ c++11 hash


【解决方案1】:

您在

中缺少一组括号
return hash<decltype(foo.i)>(foo.i);

在上面你试图构造一个std::hash,而不是调用它的operator()。你需要

return hash<decltype(foo.i)>()(foo.i);
// or
return hash<decltype(foo.i)>{}(foo.i);

括号/花括号的空集合构造散列对象,第二个集合调用它的operator()

【讨论】:

  • 谢谢!我不会想到这一点。
  • @SteveEmmerson 没问题。开始使用函子时很容易犯错误。
  • 函子每次都构造吗?如果是这样,那效率低吗?如果是这样,有没有更有效的成语?
  • @SteveEmmerson 是的,每次都会构造哈希对象,但除非它有状态,否则它是非操作的。我相信默认库是无状态的,这是常见的约定。通常,您永远不会注意到性能下降。如果您担心,您可以对其进行分析,但应该没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多