visual c++ std::tr1::hash::operator() undefined?

visual c++ std::tr1::hash::operator() undefined?

本文关键字:undefined operator hash c++ std tr1 visual      更新时间:2023-10-16

我正在将一个C++程序从Windows build with Visual C++ 2008转换为使用gcc 4.6.1构建在Linux上。有一个模块使用 <unordered_map> .在VC++中,似乎完全可以

#include <unordered_map>
...

std::tr1::unordered_map<mystruct, int> my_map;

我们实际上支持更多的编译器,而不仅仅是 gcc 4.6 和 VC++ 2008,所以使用纯 C++2011 代码是不可行的。 GCC 对 #include <unordered_map> 感到不安,抱怨这是真正的蓝色 C++2011 包含文件,所以我必须做的一件事就是将包含更改为

#include <tr1/unordered_map>
...

std::tr1::unordered_map<mystruct, int> my_map;

这行得通。很公平。不过,现在我又遇到了另一个问题。以下是mystruct的定义:

struct mystruct
{
#ifdef __cplusplus
    inline operator size_t() const
    {
        return m_val;
    }
#endif
    unsigned int m_val;
};

在VC++ 2008中,这似乎是std::hash需要专注于mystruct的。 另一方面,std::tr1::hash不喜欢这样,至少在 gcc 4.6.1 上不喜欢。它拒绝链接,抱怨std::tr1::hash<mystruct>::operator()( mystruct ) const未定义。我不确定当我做适当的tr1时,VC++ 是否会发生这种情况 - 也许它会抱怨同样的事情?我明天会尝试一下,但现在我只有一个带有 gcc 的 linux 盒子。现在,我必须这样做才能让它工作:

namespace std {
    namespace tr1 {
        std::size_t hash<mystruct>::operator()( mystruct & c ) const 
        { 
            return c.m_val; 
        }
    }
}

谁能启发我这应该如何工作?能够在您想要可哈希的类型上定义size_t运算符似乎要优雅得多,但我愿意接受在std::tr1::hash上定义operator()

更新:

按照建议,我尝试专门化整个哈希类。使用 gcc 构建,我得到

myfile.cpp:41:12: error: specialization of 'std::tr1::hash<mystruct>' after instantiation
myfile.cpp:41:12: error: redefinition of 'struct std::tr1::hash<mystruct>'
/usr/include/c++/4.6/tr1/functional_hash.h:45:12: error: previous definition of 'struct std::tr1::hash<mystruct>'

Microsoft的方式,接受到std::size_t的隐式转换,是一个扩展。

GCC的方式,专业化std::tr1::hash,是TR1实际定义的方式,现在在C++11中标准化(当然tr1::部分被删除(。

MSVC 仍应接受hash专用化,当然两者都应接受作为 Hasher 模板参数传递的全新类。

更好的风格是专门化整个类,而不仅仅是operator()函数:

namespace std {
    namespace tr1 {
        template<>
        struct hash< mystruct > {
            std::size_t operator()( mystruct & c ) const 
            { 
                return c.m_val; 
            }
        };
    }
}

由于您的mystruct是由用户定义的,因此您需要为unordered_map提供一个哈希函数:

struct my_hash {
std::size_t operator()( mystruct & c ) const 
        { 
            return c.m_val; 
        }
};
std::tr1::unordered_map<mystruct, int, my_hash> my_map;