First, as Richard Hodges says in his answer, you can't use std::weak_ptr
as a key since it is not stable. Ignoring this, we can then look at the general question: Can we use lambdas for template parameters.
The generic solution is to do as described in the following answer. There are two things to notice
- The lambda must be defined separately.
- The lambda must be passed in as an argument.
The reason for 2) is that the default constructor is removed from the type that the compiler creates for the lambda.
For std::set
this is not to bad, but consider std::unordered_map
which has no constructor taking a single key compare function:
auto compare = [](const A & lhs, const A & rhs) { return lhs==rhs; };
std::unordered_map<
A,
B,
std::hash<A>,
decltype(compare)
> map1{0, std::hash<A>{}, compare};
The first argument is the initial bucket size, and is implementation defined. I am using 0 assuming that the implementation will find an optimized value when the first item is inserted. The second is the hash function and finally the lambda.
We can improve it a bit by replacing the decltype(...)
with function<bool(A,A)>
. This allows us to declare the type in a header and therefore pass it to other functions without requiring the actual lambda to be shared. The declaration will become:
typedef std::unordered_map<
A,
B,
std::hash<A>,
std::function<bool(A,A)>
> custom_unordered_map;
And it can be used as follows:
custom_unordered_map map2{0, std::hash<A>{},
[](const A & lhs, const A & rhs) { return lhs==rhs; } };
This solution will allow custom lambdas to be used directly and also with free functions.
The main benefit with this solution is that it allows different compare functions to be used, but it is very verbose to use.
If only a single compare function is required, a less verbose solution (for the users of the type) is to define a functor:
struct Compare {
bool operator () (const A & lhs, const A & rhs) {
return lhs==rhs;
}
};
This can then be used in the normal way:
std::unordered_map<A, B, std::hash<A>, Compare> map4;
NOTE: With this solution the default constructor can be used.
The following is a full example:
#include <functional>
#include <memory>
#include <unordered_map>
using A = int;
using B = int;
struct Compare {
bool operator () (const A & lhs, const A & rhs) {
return lhs==rhs;
}
};
bool compare_func(const A & lhs, const A & rhs) {
return lhs==rhs;
}
int main() {
// Using lamda: default constructor is deleted, so the lambda
// must be passed as argument to the constructor.
auto compare = [](const A & lhs, const A & rhs) { return lhs==rhs; };
std::unordered_map<
A,
B,
std::hash<A>,
decltype(compare)
> map1{0, std::hash<A>{}, compare};
// Alternative: use std::function. More general, and allows any lambda to be used
typedef std::unordered_map<
A,
B,
std::hash<A>,
std::function<bool(A,A)>
> custom_unordered_map;
custom_unordered_map map2{0, std::hash<A>{},
[](const A & lhs, const A & rhs) { return lhs==rhs; } };
custom_unordered_map map3{0, std::hash<A>{}, compare_func};
// Use of function class
std::unordered_map<A, B, std::hash<A>, Compare> map4;
}
This can be compiled on Ubuntu 15.10 using the command g++ map_lambda.cpp --std=c++11 -o map_lambda
.
My personal opinion is to use the last solution, unless there is a need to use different functions for key comparison.