29

我有以下代码来制作unordered_set<Interval>. 这编译得很好。

struct Interval {
  unsigned int begin;
  unsigned int end;
  bool updated;   //true if concat.  initially false
  int patternIndex;  //pattern index. valid for single pattern
  int proteinIndex;   //protein index.  for retrieving the pattern
};

struct Hash {
  size_t operator()(const Interval &interval);
};

size_t Hash::operator()(const Interval &interval){
  string temp = to_string(interval.begin) + to_string(interval.end) + to_string(interval.proteinIndex);
  return hash<string>()(temp);
}

unordered_set<Interval, string, Hash> test;

但是,当我尝试使用此代码插入时,我无法编译:

for(list<Interval>::iterator i = concat.begin(); i != concat.end(); ++i){
  test.insert((*i));
}

此外,我无法从错误消息中确定问题所在,例如:

note: candidate is:
note: size_t Hash::operator()(const Interval&)
note:   candidate expects 1 argument, 2 provided  

我以为我只提供了 1 个论点...

我的插入代码有什么问题?


这是新的实例化代码:unordered_set<Interval, Hash> test; 但是,我仍然收到大量错误消息,例如:

note: candidate is:
note: size_t Hash::operator()(const Interval&) <near match>
note:   no known conversion for implicit ‘this’ parameter from ‘const Hash*’ to ‘Hash*’
4

2 回答 2

44

第一个问题:

您将string作为第二个模板参数传递给unordered_set<>类模板的实例化。第二个参数应该是你的 hasher functor 的类型,而std::string不是一个可调用的对象。

也许是要写:

unordered_set<Interval, /* string */ Hash> test;
//                      ^^^^^^^^^^^^
//                      Why this?

另外,我建议您使用除您的(成员)变量之外beginend名称,因为这些名称是 C++ 标准库的算法名称。

第二个问题:

你应该记住,哈希函数应该被限定为const,所以你的函子应该是:

struct Hash {
   size_t operator() (const Interval &interval) const {
   //                                           ^^^^^
   //                                           Don't forget this!
     string temp = to_string(interval.b) + 
                   to_string(interval.e) + 
                   to_string(interval.proteinIndex);
     return (temp.length());
   }
};

第三个问题:

最后,如果您希望std::unordered_set能够使用 类型的对象Interval,您需要定义一个与您的散列函数一致的相等运算符。默认情况下,如果你没有指定任何类型参数作为 std::unordered_set类模板的第三个参数,operator ==将被使用。

operator ==您目前的班级没有任何重载Interval,因此您应该提供一个。例如:

inline bool operator == (Interval const& lhs, Interval const& rhs)
{
    return (lhs.b == rhs.b) && 
           (lhs.e == rhs.e) && 
           (lhs.proteinIndex == rhs.proteinIndex); 
}

结论:

完成上述所有修改后,您可以在这个现场示例中看到您的代码正在编译。

于 2013-04-07T23:30:30.513 回答
3

我认为,Andy Prowl 完美地解决了您的代码问题。但是,我会将以下成员函数添加到您的Interval中,它描述了使两个间隔相同的原因:

std::string getID() const { return std::to_string(b) + " " + std::to_string(e) + " " + std::to_string(proteinIndex); }

请注意,我也听从了 Andy Prowl 的建议,将成员重命名beginb和。接下来,您可以使用lambda 表达式轻松定义散列和比较函数。因此,您可以定义如下:endeunordered_set

auto hash = [](const Interval& i){ return std::hash<std::string>()(i.getID()); };
auto equal = [](const Interval& i1, const Interval& i2){ return i1.getID() == i2.getID(); };
std::unordered_set<Interval, decltype(hash), decltype(equal)> test(8, hash, equal);

最后,出于可读性的原因,我将您的for循环转换为基于范围的for循环:

std::list<Interval> concat {{1, 2, false, 3, 4}, {2, 3, false, 4, 5}, {1, 2, true, 7, 4}};

for (auto const &i : concat)
    test.insert(i);

for (auto const &i : test)
    std::cout << i.b << ", " << i.e << ", " << i.updated << std::endl;

输出(我刚刚打印了每个的前三个成员Interval):

2, 3, 0
1, 2, 0

如您所见,只打印了两个间隔。第三个 ( {1, 2, true, 7, 4}) 没有插入到test,因为它的be、 和proteinIndex等于第一个区间 ( {1, 2, false, 3, 4}) 的。

Ideone 上的代码

于 2019-02-08T13:44:06.140 回答