问题
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 )
回答1:
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.
回答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;
}
回答3:
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
回答4:
This won't compile hashFunc
and equalFunc
are capturing lambdas. Lambdas with capture-clauses do not have an implicit conversion to pointer-to-function type. As you can see from the other answers, you need some way of getting rid of the capture-clauses, which is as simple as using hash
and equal
directly.
It seems that VS can't compile the new code. Alternatively, you can use free functions instead of lambdas and replacing decltype(...)
with aliases of function pointer types:
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);
}
来源:https://stackoverflow.com/questions/25454806/creating-unordered-set-with-lambda