Is there a way for a method, which receives two functors as arguments, to find out if they are pointing to the same function? Specifically, having a struct like this:
struct FSMAction {
void action1() const { std::cout << "Action1 called." << std::endl; }
void action2() const { std::cout << "Action2 called." << std::endl; }
void action3() const { std::cout << "Action3 called." << std::endl; }
private:
// Maybe some object-specific stuff.
};
And a method like this:
bool actionsEqual(
const std::function<void(const FSMAction&)>& action1,
const std::function<void(const FSMAction&)>& action2)
{
// Some code.
}
Is there "some code" that will return true
only for:
actionsEqual(&FSMAction::action1, &FSMAction::action1)
But not for:
actionsEqual(&FSMAction::action1, &FSMAction::action2)
Maybe this question doesn't make any sense (first clue would be that there seems to be nothing on the internet about it...). If so, could you give a hint, why, and if there are ways to accomplish something "similar"? (Basically, I'd like to have a set of callbacks with only "unique" items in the above-outlined sense.)
A raw function is eventually a pointer. You can dig it out of std::function
with std::function::target
and then it's simply a comparison of void*
.
Directly using std::function::target<T>()
as suggested in the Michael Chourdakis's answer is problematic, since to use it you have to know the actual type stored in std::function
:
Return value
A pointer to the stored function if
target_type() == typeid(T)
, otherwise a null pointer.
E.g. by using T = void (A::*)() const
you restrict yourself to only using void() const
member functions of class FSMAction
. At this point std::function
starts to be no better than a plain member function pointer.
I suggest writing a wrapper for std::function
that implements ==
/ !=
using type erasure. Here's a minimal implementation:
#include <functional>
#include <iostream>
#include <utility>
template <typename T>
class FancyFunction;
template <typename ReturnType, typename ...ParamTypes>
class FancyFunction<ReturnType(ParamTypes...)>
{
using func_t = std::function<ReturnType(ParamTypes...)>;
func_t func;
bool (*eq)(const func_t &, const func_t &) = 0;
public:
FancyFunction(decltype(nullptr) = nullptr) {}
template <typename T>
FancyFunction(T &&obj)
{
func = std::forward<T>(obj);
eq = [](const func_t &a, const func_t &b)
{
return *a.template target<T>() ==
*b.template target<T>();
};
}
explicit operator bool() const
{
return bool(func);
}
ReturnType operator()(ParamTypes ... params) const
{
return func(std::forward<ParamTypes>(params)...);
}
bool operator==(const FancyFunction &other) const
{
if (func.target_type() != other.func.target_type())
return 0;
if (!eq)
return 1;
return eq(func, other.func);
}
bool operator!=(const FancyFunction &other) const
{
return !operator==(other);
}
};
struct A
{
void foo() {}
void bar() {}
};
int main()
{
FancyFunction<void(A &)> f1(&A::foo), f2(&A::foo), f3(&A::bar);
std::cout << (f1 == f2) << '\n';
std::cout << (f1 == f3) << '\n';
}
Try it live
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With