I hope I am missing something here, because all this talk about lambdas as template arguments improving usability sounds like nonsense to me. What can you do with a lambda type that makes them so usable as template arguments?
Without requiring lambda types to be default-constructible, I don't see how this makes anything more usable.
using my_set = std::set<int, decltype([](int x, int y) { return f(x) < f(y); })>;
my_set haha_nice_try; // nope, error
my_set some_set([](int x, int y) { return f(x) < f(y); }); // erm, error!
my_set some_other_set([](int x, int y) { return f(x) < f(y); }); // ok, let's assume at least lambdas identical character-by-character are the same type; then this works
What? I have to repeat the function definition *everywhere*? And that doesn't work anyway? No, thanks.
Of course, I can just declare the lambda as a global variable instead:
auto comparison = [](int x, int y) { return f(x) < f(y); };
using my_set = std::set<int, decltype(comparison)>;
my_set haha_nice_try; // nope, still an error
my_set some_set(comparison); // ok, now this works
my_set
some_other_set(comparison); // but don't you forget to pass the comparison along every single time lest you unless the compiler's wrath upon you!
Stop it. This has no interesting advantage over using a function.
bool comparison(int x, int y) { return f(x) < f(y); };
using my_set = std::set<int, decltype(comparison)>;
my_set haha_nice_try; // also an error!
my_set some_set(comparison); // has always worked
my_set
some_other_set(comparison); // keep not forgetting it!
Note how the comparison is not really entirely part of the set. You have to keep passing it along anytime you create one. That sucks.
struct my_comparison {
bool operator()(int x, int y) { return f(x) < f(y); }
};
using my_set = std::set<int, my_comparison>;
my_set haha_nice_try; // hey, it works
my_set some_set(my_comparison{}); // you can, but why would you?
my_set some_other_set;