Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating unordered_set with lambda

How can I make unordered_set with lambda? (I know how to make it with user defined hash struct and operator==)

My current code is :

#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;
}

It give me few! number of errors (live):

Note that I make a lambda for returning std::function (equalFunc,hashFunc) because it seems that in unordered_set some functions are trying to copy return type of that lambdas !

Also it's weird that gcc 4.8 compile that code fine ! ( live )

like image 301
uchar Avatar asked Aug 22 '14 20:08

uchar


3 Answers

You don't need hashFunc and equalFunc after all, just use the 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

like image 150
101010 Avatar answered Oct 11 '22 12:10

101010


There's no need for the std::function abstraction in your code. Just obtain the lambda types directly via decltype for unordered_set's template arguments

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);

And in places where you're simply performing element-wise comparison of two structs, I find it easier to use std::tie instead

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

The above code compiles on both gcc and clang, but not on VS2013 because of this bug. The VS standard library implementation tries to default construct the lambda type somewhere, which is going to fail because the default constructor is deleted. std::function can be used as a workaround for VS2013, but I'd stick to defining a struct with an overloaded operator() instead.

like image 34
Praetorian Avatar answered Oct 11 '22 12:10

Praetorian


#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;
}
like image 38
Piotr Skotnicki Avatar answered Oct 11 '22 14:10

Piotr Skotnicki