【问题标题】:unordered_map constructor error (equal_to templated function)unordered_map 构造函数错误(equal_to 模板函数)
【发布时间】:2026-01-11 00:40:02
【问题描述】:

我以为我可以有一个指向完全专业化的模板函数的指针,但以下代码无法编译 (MSVC2012)

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>

using namespace std;

unsigned long hashing_func(string key)
{
    unsigned long hash = 0;
    for(int i=0; i<key.size(); i++)
    {
        hash += (71*hash + key[i]) % 5;
    }
    return hash;
}

bool key_equal_fn2(string t1, string t2)
{
    return t1 == t2;
}


template<class T> bool key_equal_fn(T t1, T t2)
{
    return t1 == t2;
}

template <> bool key_equal_fn<string>(string t1, string t2)
{
    return !(t1.compare(t2));
}

int main ()
{
    unordered_map<string, string>::size_type n = 5;
    unordered_map<string, string> mymap(n, (const std::hash<string> &)hashing_func, (const std::equal_to<string> &)(key_equal_fn<string>)) ;

    mymap["paul"] = "jenna";
    mymap["frank"] = "ashley";


    return 0;
}

构造函数行返回以下错误:

错误 C2440: 'type cast' : 无法从 'bool (__cdecl *)(T,T)' 转换 to 'const std::equal_to<_ty> &'

【问题讨论】:

  • 无法将参数 3 从 'bool (__cdecl *)(T,T)' 转换为 'const std::equal_to<_ty> &'
  • 从不使用 C 风格的强制转换。
  • 没有转换。 (1) 将 equal_to&lt;string&gt; 类型的对象提供给 unordered_map&lt;...&gt; 的构造函数,或者 (2) 提供您自己的类型,而不是 unordered_map&lt;...&gt; 的默认模板参数。

标签: c++ c++11


【解决方案1】:

hashing_funckey_equal_fn 都应该是函子对象(而不是函数)。另外,它们的类型必须提供给unordered_map模板,即map应该有这个类型:

unordered_map<string, string, hashing_func, key_equal_fn>

其中hashing_funckey_equal_fn 是函子类:

struct hashing_func {
    unsigned long operator()(const string& key) const {
        unsigned long hash = 0;
        for(size_t i=0; i<key.size(); i++)
            hash += (71*hash + key[i]) % 5;
        return hash;
    }
};

struct key_equal_fn {
    bool operator()(const string& t1, const string& t2) const {
        return !(t1.compare(t2));
    }
};

那么,mymap 是这样定义的:

typedef unordered_map<string, string, hashing_func, key_equal_fn> MapType;
MapType::size_type n = 5;
MapType mymap(n, hashing_func(), key_equal_fn());

或者,hashing_func 和/或key_equal_fn 可以是函数,但您必须将它们包装到std::function 对象中。也就是说,

unsigned long hashing_func(const string& key) {
    unsigned long hash = 0;
    for(size_t i=0; i<key.size(); i++)
      hash += (71*hash + key[i]) % 5;
    return hash;
}

bool key_equal_fn(const string& t1, const string& t2){
  return !(t1.compare(t2));
}

并以这种方式定义mymap

typedef unordered_map<string, string,
    std::function<unsigned long(const string&)>,
    std::function<bool(const string&, const string&)>> MapType;

MapType::size_type n = 5;
MapType mymap(n, hashing_func, key_equal_fn);

如果您愿意,可以使用 lambdas 并避免编写两个函数或仿函数类:

typedef unordered_map<string, string,
    std::function<unsigned long(const string&)>,
    std::function<bool(const string&, const string&)>> MapType;

MapType mymap(n,
  [](const string& key) -> unsigned long {
      unsigned long hash = 0;
      for(size_t i=0; i<key.size(); i++)
        hash += (71*hash + key[i]) % 5;
      return hash;
  },
  [](const string& t1, const string& t2) {
       return !(t1.compare(t2));
  });

最后,我最喜欢的是 all-lambdas 解决方案

auto hashing_func = [](const string& key) -> unsigned long {
    unsigned long hash = 0;
    for(size_t i=0; i<key.size(); i++)
        hash += (71*hash + key[i]) % 5;
    return hash;
};

auto key_equal_fn = [](const string& t1, const string& t2) {
    return !(t1.compare(t2));
};

typedef unordered_map<string, string,
    decltype(hashing_func), decltype(key_equal_fn)> MapType;

MapType::size_type n = 5;
MapType mymap(n, hashing_func, key_equal_fn);

【讨论】:

  • 感谢您的 sn-ps(std::function 解决了问题),我设法编译了我的代码,但现在我遇到了不同的问题,所以我发布了一个新问题。谢谢!
  • 如果使用 ReSharper,使用Alt-Insert 获取Generate Code,在类中生成EqualityHash Function,并将代码粘贴到上面的样板文件中。节省打字。