当用户在 unordered_map 中自定义哈希函数时,无法解码 g++ 中的模糊编译器错误

Posted

技术标签:

【中文标题】当用户在 unordered_map 中自定义哈希函数时,无法解码 g++ 中的模糊编译器错误【英文标题】:Cannot decode an obscured compiler error in g++ when user custom hash function in unordered_map 【发布时间】:2016-03-17 04:07:34 【问题描述】:

这是我要编译的代码:

#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <vector>
#include <string>

using namespace std;

namespace _LEET_MAX_POINTS_ON_A_LINE

    struct Point
    
        int x;
        int y;
        Point() : x(0), y(0) 
        Point(int a, int b) : x(a), y(b) 
    ;

    struct SlantedLine
    
    public:
        int slope_numerator;
        int slope_denominator;
        int intercept_numerator;
        int intercept_denominator;
    ;

    struct SlantedLineHash
    
        size_t operator()(const SlantedLine& k) const
        
            return k.slope_numerator ^ k.slope_denominator ^ k.intercept_numerator ^ k.intercept_denominator;
        
    ;

    struct SlantedLineEqual
    
        size_t operator()(const SlantedLine& line1, const SlantedLine& line2) const
        
            return (line1.slope_numerator == line2.slope_numerator) && (line1.slope_denominator == line2.slope_denominator) && (line1.intercept_numerator == line2.intercept_numerator) && (line1.intercept_denominator == line2.intercept_denominator);
        
    ;

    class Solution
    
    public:
        int maxPoints(vector<Point>& points)
        
            if (points.size() == 0)
            
                return 0;
            

            unordered_map<SlantedLine, unordered_set<int>, SlantedLineHash, SlantedLineEqual> slantedLineToPointsMap;
            unordered_map<int, unordered_set<int>> verticalLineToPointsMap;
            for (size_t i = 0; i < points.size(); i++)
            
                for (size_t j = i + 1; j < points.size(); j++)
                
                    int x1 = points[i].x;
                    int y1 = points[i].y;
                    int x2 = points[j].x;
                    int y2 = points[j].y;

                    if (x1 == x2)
                    
                        unordered_map<int, unordered_set<int>>::iterator probe = verticalLineToPointsMap.find(x1);
                        if (probe == verticalLineToPointsMap.end())
                        
                            unordered_set<int> points;
                            points.insert(i);
                            points.insert(j);
                            verticalLineToPointsMap.insert(pair<int, unordered_set<int>>(x1, points));
                        
                        else
                        
                            probe->second.insert(i);
                            probe->second.insert(j);
                        
                    
                    else
                    
                        int slope_numerator = y2 - y1;
                        int slope_denominator = x2 - x1;
                        int intercept_numerator = y1 * x2 - x1 * y2;
                        int intercept_denominator = x2 - x1;
                        simplify_fraction(&slope_numerator, &slope_denominator);
                        simplify_fraction(&intercept_numerator, &intercept_denominator);
                        SlantedLine line;
                        line.slope_numerator = slope_numerator;
                        line.slope_denominator = slope_denominator;
                        line.intercept_numerator = intercept_numerator;
                        line.intercept_denominator = intercept_denominator;
                        unordered_map<SlantedLine, unordered_set<int>, SlantedLine, SlantedLineEqual>::iterator probe = slantedLineToPointsMap.find(line);
                        if (probe == slantedLineToPointsMap.end())
                        
                            unordered_set<int> points;
                            points.insert(i);
                            points.insert(j);
                            slantedLineToPointsMap.insert(pair<SlantedLine, unordered_set<int>>(line, points));
                        
                        else
                        
                            probe->second.insert(i);
                            probe->second.insert(j);
                        
                    
                
            

            size_t maxPoints = 0;
            for (unordered_map<int, unordered_set<int>>::iterator i = verticalLineToPointsMap.begin(); i != verticalLineToPointsMap.end(); i++)
            
                maxPoints = max(maxPoints, i->second.size());
            
            for (unordered_map<SlantedLine, unordered_set<int>, SlantedLine, SlantedLineEqual>::iterator i = slantedLineToPointsMap.begin(); i != slantedLineToPointsMap.end(); i++)
            
                maxPoints = max(maxPoints, i->second.size());
            

            return maxPoints;
        
    private:
        void simplify_fraction(int* numerator, int* denominator)
        
            int common_factor = gcd(*numerator, *denominator);
            *numerator /= common_factor;
            *denominator /= common_factor;
            if (*denominator < 0)
            
                *numerator *= -1;
                *denominator *= -1;
            
        

        int gcd(int a, int b)
        
            if (a < 0)
            
                return gcd(-a, b);
            
            else if (b < 0)
            
                return gcd(a, -b);
            
            else if (b > a)
            
                return gcd(b, a);
            
            else
            
                if (b == 0)
                
                    return a;
                
                else
                
                    return gcd(b, a % b);
                
            
        
    ;
;

using namespace _LEET_MAX_POINTS_ON_A_LINE;

int LEET_MAX_POINTS_ON_A_LINE()

    Solution solution;
    return 0;

代码在 Visual Studio 2015 上编译良好(带有一些不相关的警告),但在 g++ 上却惨遭失败(如在 ideone 上:https://ideone.com/d1Rs1I)

这是编译器的输出:

In file included from /usr/include/c++/5/bits/hashtable.h:35:0,
                 from /usr/include/c++/5/unordered_map:47,
                 from prog.cpp:1:
/usr/include/c++/5/bits/hashtable_policy.h: In instantiation of 'struct std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine>':
/usr/include/c++/5/type_traits:137:12:   required from 'struct std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> >'
/usr/include/c++/5/type_traits:148:38:   required from 'struct std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
/usr/include/c++/5/bits/unordered_map.h:100:66:   required from 'class std::unordered_map<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, std::unordered_set<int>, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLineEqual>'
prog.cpp:96:102:   required from here
/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to '(const _LEET_MAX_POINTS_ON_A_LINE::SlantedLine) (const _LEET_MAX_POINTS_ON_A_LINE::SlantedLine&)'
  noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
                                  ^
In file included from /usr/include/c++/5/bits/move.h:57:0,
                 from /usr/include/c++/5/bits/stl_pair.h:59,
                 from /usr/include/c++/5/utility:70,
                 from /usr/include/c++/5/unordered_map:38,
                 from prog.cpp:1:
/usr/include/c++/5/type_traits: In instantiation of 'struct std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >':
/usr/include/c++/5/bits/unordered_map.h:100:66:   required from 'class std::unordered_map<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, std::unordered_set<int>, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLineEqual>'
prog.cpp:96:102:   required from here
/usr/include/c++/5/type_traits:148:38: error: 'value' is not a member of 'std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> >'
     : public integral_constant<bool, !_Pp::value>
                                      ^
In file included from /usr/include/c++/5/unordered_map:48:0,
                 from prog.cpp:1:
/usr/include/c++/5/bits/unordered_map.h: In instantiation of 'class std::unordered_map<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, std::unordered_set<int>, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLineEqual>':
prog.cpp:96:102:   required from here
/usr/include/c++/5/bits/unordered_map.h:100:66: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc>  _Hashtable;
                                                                  ^
/usr/include/c++/5/bits/unordered_map.h:107:45: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::key_type key_type;
                                             ^
/usr/include/c++/5/bits/unordered_map.h:108:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::value_type value_type;
                                               ^
/usr/include/c++/5/bits/unordered_map.h:109:48: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::mapped_type mapped_type;
                                                ^
/usr/include/c++/5/bits/unordered_map.h:110:43: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::hasher hasher;
                                           ^
/usr/include/c++/5/bits/unordered_map.h:111:46: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::key_equal key_equal;
                                              ^
/usr/include/c++/5/bits/unordered_map.h:112:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::allocator_type allocator_type;
                                                   ^
/usr/include/c++/5/bits/unordered_map.h:117:45: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::pointer  pointer;
                                             ^
/usr/include/c++/5/bits/unordered_map.h:118:50: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::const_pointer const_pointer;
                                                  ^
/usr/include/c++/5/bits/unordered_map.h:119:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::reference  reference;
                                               ^
/usr/include/c++/5/bits/unordered_map.h:120:52: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::const_reference const_reference;
                                                    ^
/usr/include/c++/5/bits/unordered_map.h:121:46: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::iterator  iterator;
                                              ^
/usr/include/c++/5/bits/unordered_map.h:122:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::const_iterator const_iterator;
                                                   ^
/usr/include/c++/5/bits/unordered_map.h:123:51: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::local_iterator local_iterator;
                                                   ^
/usr/include/c++/5/bits/unordered_map.h:124:57: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::const_local_iterator const_local_iterator;
                                                         ^
/usr/include/c++/5/bits/unordered_map.h:125:47: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::size_type  size_type;
                                               ^
/usr/include/c++/5/bits/unordered_map.h:126:52: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       typedef typename _Hashtable::difference_type difference_type;
                                                    ^
/usr/include/c++/5/bits/unordered_map.h:280:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       operator=(initializer_list<value_type> __l)
       ^
/usr/include/c++/5/bits/unordered_map.h:379:2: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
  emplace(_Args&&... __args)
  ^
/usr/include/c++/5/bits/unordered_map.h:432:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       insert(const value_type& __x)
       ^
/usr/include/c++/5/bits/unordered_map.h:439:2: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
  insert(_Pair&& __x)
  ^
/usr/include/c++/5/bits/unordered_map.h:499:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       insert(initializer_list<value_type> __l)
       ^
/usr/include/c++/5/bits/unordered_map.h:645:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       equal_range(const key_type& __x)
       ^
/usr/include/c++/5/bits/unordered_map.h:649:7: error: 'value' is not a member of 'std::__not_<std::__and_<std::__is_fast_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine>, std::__detail::__is_noexcept_hash<_LEET_MAX_POINTS_ON_A_LINE::SlantedLine, _LEET_MAX_POINTS_ON_A_LINE::SlantedLine> > >'
       equal_range(const key_type& __x) const
       ^
prog.cpp: In member function 'int _LEET_MAX_POINTS_ON_A_LINE::Solution::maxPoints(std::vector<_LEET_MAX_POINTS_ON_A_LINE::Point>&)':
prog.cpp:97:29: error: 'probe' was not declared in this scope
                         if (probe == slantedLineToPointsMap.end())
                             ^
prog.cpp:118:142: error: 'i' was not declared in this scope
             for (unordered_map<SlantedLine, unordered_set<int>, SlantedLine, SlantedLineEqual>::iterator i = slantedLineToPointsMap.begin(); i != slantedLineToPointsMap.end(); i++)
                                                                                                                                          ^

编译器错误输出看起来与此线程上发布的非常相似。

Creating an std::unordered_map with an std::pair as key

但我确信我的哈希函数是 const。不知道为什么它仍然抱怨我的哈希函数不是 const。

【问题讨论】:

在 xcode 上似乎也可以正常编译:( 如果它在 xcode 上编译得很好,那么 xcode 就坏了:) 【参考方案1】:

您使用的迭代器类型不正确。

你有:

unordered_map<SlantedLine, unordered_set<int>, SlantedLineHash, SlantedLineEqual> slantedLineToPointsMap;
...
unordered_map<SlantedLine, unordered_set<int>, SlantedLine, SlantedLineEqual>::iterator probe = slantedLineToPointsMap.find(line);
...
for (unordered_map<SlantedLine, unordered_set<int>, SlantedLine, SlantedLineEqual>::iterator i = slantedLineToPointsMap.begin(); i != slantedLineToPointsMap.end(); i++)

您可以看到您指定了错误的迭代器类型 - 将类型更改为 auto(这将有助于避免此类问题)或使用 unordered_map&lt;SlantedLine, unordered_set&lt;int&gt;, SlantedLineHash, SlantedLineEqual&gt;::iterator

原来的错误并没有那么可怕——它告诉你的是编译器需要void SlantedLine::operator()(const SlantedLine&amp;) const。如果你像这样将它添加到你的代码中:

struct SlantedLine

public:
    int slope_numerator;
    int slope_denominator;
    int intercept_numerator;
    int intercept_denominator;

    void operator()(const SlantedLine&) const
    

    
;

它编译。它确实要求这个运算符,因为它认为 SlantedLine 是哈希类型。

【讨论】:

谢谢,应该用typedef,不小心复制粘贴出错了。 @AndrewAu 我还是会选择auto 代替你,基本上没有理由不这样做:)

以上是关于当用户在 unordered_map 中自定义哈希函数时,无法解码 g++ 中的模糊编译器错误的主要内容,如果未能解决你的问题,请参考以下文章

C++ 哈希表 - 如何解决 unordered_map 与自定义数据类型作为键的冲突?

unordered_map/set自定义哈希函数

Java - 自定义哈希映射/表的一些要点

C++之unordered_map和unordered_set以及哈希详解

unordered_map 哈希函数 / 如何防止 unordered_map 被卡

C++之unordered_map和unordered_set以及哈希详解