I'd like to have a class template with parameters with and without defaults. And I'd like a parameter with a default to be able to be deduced from the constructor. An example:
template <typename T, typename Compare = std::less<T> >
struct foo {
foo(const Compare& c = Compare{}) { }
};
foo<int> x; // Works, c = std::less<int>{}
foo<int, std::greater<int>> y; // Works, c = std::greater<int>{}
auto cmp = [](const int&, const int&){ return true; };
foo<int, decltype(cmp)> z(cmp); // Works (with C++20), c = cmp
foo<int> bad(cmp); // Fails
The issue with the bad code seems to be that since only template parameter T
is provided, the default of std::less<int>
is used for Compare
. This makes the constructor's signature foo(const std::less<int>&)
, which is not compatible with the call of foo(<lambda>)
, as the lambda can't be converted to std:less<int>
.
If another argument is added to the constructor, so that all template parameters can be deduced from constructor arguments, then it works.
template <typename T, typename Compare = std::less<T> >
struct bar {
bar(T, const Compare& c = Compare{}) { }
};
bar z2(int{}, [](){return true;});