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

Cannot decode an obscured compiler error in g++ when user custom hash function in unordered_map

这是我要编译的代码:

#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++)
                                                                                                                                          ^

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

但我确定我的散列函数是常量。不知道为什么它仍然抱怨我的哈希函数不是 const。

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

你有:

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<SlantedLine, unordered_set<int>, SlantedLineHash, SlantedLineEqual>::iterator.

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

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

    void operator()(const SlantedLine&) const
    {

    }
};

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