3

my understanding is that greater_equal<double> is a functor that has a signature of function<bool (double, double)>, so I have tried to perform the following,

#include <functional>
#include <memory>

using namespace std;

int main() {
    std::shared_ptr<std::function<bool (double, double)>> f;
    auto f1 =make_shared<greater_equal<double>>();
    auto f2 = make_shared<less_equal<double>>();
    f = f1;
}

To my surprise this wont compile because,

'': cannot convert from 'const std::shared_ptrstd::greater_equal<double>' to 'std::shared_ptr<std::function<bool (double,double)>>'

I am not sure why, what I need is similar to the spirit in the above snippet, I will have a member field of function, std::shared_ptr<std::function<bool (double, double)>> and I need to assign either <greater_equal<double> or less_equal<double> base on some condition, how should I achieve this?

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
tesla1060
  • 2,621
  • 6
  • 31
  • 43
  • What's to be surprised about there? It is a type which overloads `operator()`, it is not implicitly convertible to a `std::function`. You need a lambda if that's what you want to do. The overloaded operator might be convertible if you know the actual incantation, but the object itself is not a lambda. – Tanveer Badar Sep 02 '20 at 06:23
  • @TanveerBadar Why isn't it convertible? It is (an instance of that type, that is). OP just does it incorrectly. – HolyBlackCat Sep 02 '20 at 06:25
  • @HolyBlackCat Color me surprised then. :) If it is supposed to be convertible, then this might be an issue with the compiler OP is using. Or that. – Tanveer Badar Sep 02 '20 at 06:26
  • Note that the problem is with `shared_ptr` here. You can store `std::greater_equal` into `std::function`. But in`shared_ptr` construction/assignment, you can work only with objects that have [_compatible_ pointers](https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr), which is not your case. – Daniel Langr Sep 02 '20 at 06:45
  • @TanveerBadar It is convertible since `std::function` has a corresponding (non-explicit) converting constructor. You can easily write `std::function f = std::greater_equal{};`. – Daniel Langr Sep 02 '20 at 06:48
  • If you [look it up](https://en.cppreference.com/w/cpp/utility/functional/greater_equal), you will see that your assumption about the type is wrong. – molbdnilo Sep 02 '20 at 07:27

1 Answers1

4

What you wrote would work if std::greater_equal<double> and std::less_equal<double> inherited from std::function<bool(double, double)>, which they don't do.

But since std::function<bool(double, double) is constructible from an instance of std::greater_equal<double> (and less_equal), you can do this instead:

auto f1 = std::make_shared<std::function<bool(double, double)>>(std::greater_equal<double>{});

But I don't think you want std::function in the first place.

greater_equal<double> is a functor that has a signature of function<bool (double, double)>

Yes, its operator() has (double, double) parameters and returns bool, but it's not related to std::function.

std::function is a wrapper class that can store any object it considers to be callable. It accepts slight variations in signature (e.g. even though less/greater_equal accept parameters by const references, and you told std::function that parameters should be passed by value, it still works), and it can store objects with a state (with data members). Those features come with an overhead.


Judging by

I need to assign either greater_equal<double> or less_equal<double> base on some condition

you need none of those std::function features.

You could rather use a function pointer (which requires signatures to match exactly, and can't store any state):

bool (*ptr)(double, double) = [](double a, double b)
{
    return a <= b;
};

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207