如何在 unordered_map 的键中使用 std::tr1::function 对象?

Posted

技术标签:

【中文标题】如何在 unordered_map 的键中使用 std::tr1::function 对象?【英文标题】:How can I use a std::tr1::function object in a key to unordered_map? 【发布时间】:2011-12-08 01:35:48 【问题描述】:

我正在尝试形成一个 std::tr1::unordered_map,其中键类型是一个包含回调函数的结构,我正在为此使用 std::tr1::function。我遇到了两个问题:1)函数对象似乎不具有可比性,如 Boost.Function 文档所示; 2)我看不到如何实现散列函数,因为我无法从函数对象中获取常规函数指针(或我可以用于散列的其他东西)。

示例代码如下:

#include <boost/functional/hash.hpp>
#include <boost/tr1/functional.hpp>
#include <boost/tr1/unordered_map.hpp>
#include <iostream>

int f(int) 
typedef std::tr1::function<int(int)> callback;

struct Record

  callback func;
  // More members...

  // Requirements for unordered_map key.
  friend bool operator==(Record const & lhs, Record const & rhs)
     return lhs.func == rhs.func;  // error: ambiguous
  friend std::size_t hash_value(Record const & arg)
     return boost::hash<void *>(arg.func.get());  // error: no member get()
;

int main()

  std::tr1::unordered_map<Record, int> map;
  Record a = f;
  map[a] = 0;

  return 0;

这里是第一个错误的一些细节:

test.cpp: In function bool operator==(const Record&, const Record&):
test.cpp:16: error: ambiguous overload for operator== in lhs->Record::func == rhs->Record::func
test.cpp:16: note: candidates are: operator==(void (boost::function1<int, int>::dummy::*)(), void (boost::function1<int, int>::dummy::*)()) <built-in>
<root>/boost/function/function_template.hpp:1024: note:                 void boost::operator==(const boost::function1<R, T0>&, const boost::function1<R, T0>&) [with R = int, T0 = int]

对于第二个错误,显然没有函数<...>::get 成员,但我应该使用什么来代替?

我正在使用 Boost 版本 1.42 和 g++ 4.2.2。感谢您的帮助。

更新

发布的问题的答案是“你不能”。 tr1::function 对象是可散列的(例如,使用 boost::hash),但不能相等比较。如果您想在哈希键中使用函数,请重新考虑方法或找到解决方法。

【问题讨论】:

您总是可以决定在哈希计算中不包括func。这可能并不理想,但它肯定是有效的。如果您预计 Record 的其他成员通常会有所不同,那么它也可能不会产生任何实际影响。 事实上,这是个好主意。我可以在单独的字段“id”中捕获使记录相等或不相等的原因,然后对其进行哈希处理。让 operator== 为函数工作肯定会更优雅,但看起来不太可能。 如果其他人感到困惑,Boost.Function documentation 中有两个部分讨论比较。在“常见问题”下,它解释了为什么无法比较函数对象。在“比较 Boost.Function 函数对象”下,它描述了如何比较函数对象。由于第二页最近更新,我认为常见问题解答刚刚过时。实际上,两者都是正确的。函数包装器可以与任何可存储在包装器中的东西进行比较,但不能与另一个包装器进行比较。 【参考方案1】:

似乎TR1特别要求

template<class Function2> bool operator==(const function<Function2>&);
template<class Function2> bool operator!=(const function<Function2>&);

保持未定义(3.7.2.6),所以至少你必须找到另一种获得平等的方法。此外,我也没有在论文中找到对get() 成员方法的任何引用。

【讨论】:

使用 get() 应该传达我正在尝试做的事情的要点; tr1::function 中没有成员。不过,今天重新审视一下,这个特殊问题变得清晰起来。我只是没有足够仔细地阅读 boost::hash 的文档,并试图像函数一样调用它。它是一种类型。我会为此添加一个答案。 谢谢@matthias,你是对的。没有比较两个 tr1::function 对象的 operator== 或 operator!= 函数(尽管可以将 tr1::function 与可以存储在函数中的任何对象 A 进行比较)。【参考方案2】:

我可以回答我自己关于 hash_value 的问题。这是使用 tr1::function 调用 boost::hash 的正确方法:

friend std::size_t hash_value(Record const & arg)

  boost::hash<callback> hasher;
  return hasher(arg.func);

【讨论】:

【参考方案3】:

使用function::target 讨论了here 和here 的一些想法。您可能还需要考虑 Boost.Signals 库,因为它旨在支持回调注册。

【讨论】:

感谢您的信息。这似乎证实了如果我尝试使函数成为哈希值的一部分,我尝试进行的比较将会很丑陋。

以上是关于如何在 unordered_map 的键中使用 std::tr1::function 对象?的主要内容,如果未能解决你的问题,请参考以下文章

Swift 在尝试从存在的键中获取值时得到 Nil [关闭]

使用 std::string 作为字典顺序的键对 unordered_map 进行排序

无法从分离的线程访问 C++ unordered_map 中的键值对

KendoUI 图表不接受 JSON 数据的键中的数字

查找不存在的键时,unordered_map 会返回啥

使用项目加载器scrapy获取键中的值