Is there an objective reason why the explicitly instantiated std::less, std::greater and similar offer no conversion to function pointer?

151 views Asked by At

Stateless lambdas can be converted to function pointers, e.g. this is valid,

using Fun = bool(*)(int, int);
constexpr auto less = [](int a, int b){ return a < b; };
Fun f{less};

but objects like std::less<int>{} can't.

I do understand why std::less<>{} can't, because it's operator() is not instantiated until the object is applied to some arguments, so how could it be converted to a Fun, if the decision of what its template argument(s) are is not been taken yet?

But std::less<int>{} seems just the same as the lambda I've written above, no?

2

There are 2 answers

0
Nicol Bolas On BEST ANSWER

Stateless lambdas can be converted to function pointers, e.g. this is valid, [...] but objects like std::less<int>{} can't.

"Can't" is the wrong word. After all, a "stateless lambda" is just an object, and it doesn't have any magical rules compared to other objects. A lambda is a class type like any other. It is simply generated by the compiler. You can hand write a type that does anything a lambda does; it'd just take more code.

The ability of stateless lambdas to be converted to function pointers is similarly not magic. Any type can have conversion operators defined for it, allowing them to be implicitly convertible to arbitrary types. For a stateless lambda, the compiler simply generates a conversion operator to a pointer to an appropriate function pointer signature.

std::less<T> could have an operator bool (*)(T const&, T const&)() const overload that returns a pointer to a function that does this comparison. But it doesn't. There's nothing stopping it from doing this, save the fact that the C++ standard doesn't say that the type shall have such an interface.

And this hasn't happened because nobody has proposed it for standardization.

1
Marshall Clow On

std::less<int> has a non-static member function (operator()) that takes two ints and returns a bool.

This is wrong (as @HolyBlackCat pointed out):

It can be converted to a function pointer bool (*)(const std::less<int> *, const int &, const int &). (or to a pointer to member function)

It can be converted to a pointer to member function: bool (std::less<int>::*)(const int &, const int &) const

If it had been defined as a static member function, then the conversion would to bool (*) (const int &, const int &) would be valid.