用lambda创建unordered_set

时间:2014-08-22 20:04:10

标签: c++ c++11 hash lambda unordered-set

如何使用lambda制作unordered_set? (我知道如何使用用户定义的哈希结构和operator==

我目前的代码是:

#include <unordered_set>
#include <functional>

struct Point
{
    float x;
    float y;
    Point() : x(0), y(0) {}
};

int main()
{
    auto hash=[](const Point& pt){
        return (size_t)(pt.x*100 + pt.y);
    };
    auto hashFunc=[&hash](){
        return  std::function<size_t(const Point&)> (hash);
    };
    auto equal=[](const Point& pt1, const Point& pt2){
        return ((pt1.x == pt2.x) && (pt1.y == pt2.y));
    };
    auto equalFunc=[&equal](){
        return std::function<size_t(const Point&,const Point&)> (equal);
    };
    using PointHash=std::unordered_set<Point,decltype(hashFunc),decltype(equalFunc)>;

    PointHash Test(10,hashFunc,equalFunc);

    return 0;
}

它给我的几个!错误数量(live):

请注意,我为返回std::functionequalFunchashFunc)创建了一个lambda,因为似乎在unordered_set中某些函数正在尝试复制该lambdas的返回类型!

gcc 4.8编译该代码还好,这很奇怪! (live

4 个答案:

答案 0 :(得分:10)

您的代码中不需要std::function抽象。只需通过decltype直接获取unordered_set模板参数的lambda类型

auto hash=[](const Point& pt){
    return (size_t)(pt.x*100 + pt.y);
};

auto equal=[](const Point& pt1, const Point& pt2){
    return ((pt1.x == pt2.x) && (pt1.y == pt2.y));
};

using PointHash = std::unordered_set<Point, decltype(hash), decltype(equal)>;

PointHash Test(10, hash, equal);

在您只是简单地对两个结构进行元素比较的地方,我发现使用std::tie更容易

auto equal=[](const Point& pt1, const Point& pt2){
    return std::tie(pt1.x, pt1.y) == std::tie(pt2.x, pt2.y);
};

以上代码在gcc和clang上编译,但由于this bug而在VS2013上编译。 VS标准库实现尝试默认在某处构造lambda类型,这将失败,因为删除了默认构造函数。 std::function可以用作VS2013的变通方法,但我仍然坚持定义struct并重载operator()

答案 1 :(得分:2)

#include <vector>
#include <unordered_set>
#include <functional>

struct Point
{
    float x;
    float y;
    Point() : x(0), y(0) {}
};

int main()
{
    auto hash = [](const Point& pt){
        return (size_t)(pt.x*100 + pt.y);
    };

    using hashFunc = std::function<size_t(const Point&)>;

    auto equal = [](const Point& pt1, const Point& pt2){
        return ((pt1.x == pt2.x) && (pt1.y == pt2.y));
    };

    using equalFunc = std::function<size_t(const Point&,const Point&)>;

    using PointHash = std::unordered_set<Point,hashFunc,equalFunc>;

    PointHash Test(10, hash, equal);

    return 0;
}

答案 2 :(得分:2)

毕竟你不需要hashFuncequalFunc,只需使用lambdas:

auto hash = [](const Point& pt){ return (size_t)(pt.x*100 + pt.y); };

auto equal = [](const Point& pt1, const Point& pt2) {return ((pt1.x == pt2.x) && (pt1.y == pt2.y)); };

using PointHash=std::unordered_set<Point,decltype(hash),decltype(equal)>;
PointHash Test(10,hash,equal);

LIVE DEMO

答案 3 :(得分:1)

这不会编译hashFuncequalFunc 捕获 lambdas。带有capture子句的Lambda没有隐式转换为指向函数的类型。从其他答案中可以看出,你需要一些摆脱capture-clauses的方法,就像直接使用hashequal一样简单。

It seems that VS can't compile the new code。或者,您可以使用自由函数而不是lambda,并将decltype(...)替换为函数指针类型的别名:

std::size_t hash(const Point& pt)
{
    return pt.x * 100 + pt.y;
}

bool equal(const Point& pt1, const Point& pt2)
{
    return ((pt1.x == pt2.x) && (pt1.y == pt2.y));
}

int main()
{
    using hash_type = std::size_t (*)(const Point&);
    using equal_type = bool (*)(const Point&, const Point&);
    using PointHash = std::unordered_set<Point, hash_type, equal_type>;

    PointHash Test(10, hash, equal);
}