2

Since I can not compare std::function objects and only store member functions and functions, I tried to create my own class. Where I have encountered the problem that I have to compare functions and member functions of different classes with each other. I've considered the following solution, but I'm not sure if that's valid:

template<class ClassT, class RetT, class... Args>
uint32_t getMethodAddress(RetT(ClassT::*mFunc)(Args...))
{
    union Method
    {
        RetT(ClassT::*mFunc)(Args...);
        uint32_t address;
    };

    return Method{ mFunc }.address;
}

Is it possible to save the address of each method by uint32_t and can I compare this address without any nasty surprises with other functions and methods?


If anyone wonders what the class looks like:

// Function.hpp
template<class RetT, class... Args>
class Function
{
public:
    explicit Function(RetT(*func)(Args...))
    {
        _in::Function<RetT, Args...>* pTmp{ new _in::Function<RetT, Args...>{ func } };
        _pFunc = pTmp;
    }

    template<class ClassT>
    explicit Function(ClassT* pObj, RetT(ClassT::*mFunc)(Args...))
    {
        _in::MFunction<ClassT, RetT, Args...>* pTmp{ new _in::MFunction<ClassT, RetT, Args...>{ pObj, mFunc } };
        _pFunc = pTmp;
    }

    RetT operator()(Args... args)
    {
        return (*_pFunc)(args...);
    }

    bool operator==(const Function& rhs)
    {
        return _pFunc->addr() == rhs._pFunc->addr(); // Is that valid?
    }

private:
    _in::BaseFunction<RetT, Args...>* _pFunc{ nullptr };
};
SOUser
  • 105
  • 9
  • 3
    Your use of the union is undefined behavior – Cruz Jean Mar 15 '19 at 22:49
  • @CruzJean When I use the union, I get back an address that matches the address I see in debug mode for this method. In this sense, the union is already working, what exactly is undefined behavior? – SOUser Mar 15 '19 at 22:55
  • 2
    Member pointers do not mix with ordinary pointers, and it's misleading to think of a member function pointer as an "address" in general. You _can_ test two member non-virtual pointers from the same class for equality, but that's about it. What do you need this for? It would help to know the overall problem you're trying to solve. Related reading: https://stackoverflow.com/questions/1765431/c-comparing-member-function-pointers – alter_igel Mar 15 '19 at 22:57
  • 2
    @SOUser It's Undefined Behavior to read from an inactive member of a union. Despite common misconceptions, unions are _not_ for type punning, they are only for saving space. – alter_igel Mar 15 '19 at 22:58
  • 1
    @SOUser I didn't say it wouldn't work. I just said it's undefined behavior (to access a union member that wasn't most-recently assigned). Compilers are free to do whatever they want, but it's not standard conforming. Also, in 64-bit mode it's more-obvious what the problem is (i.e. when pointers are 64 bit). – Cruz Jean Mar 15 '19 at 22:59
  • 2
    It would help if you explain what led you to this design. There's probably an elegant solution to your overall problem, but I don't think you'll find one this way. – alter_igel Mar 15 '19 at 23:02
  • @CruzJean Ah, oke. Well, thank you, I know what you mean, so I should generally look for a standardized solution. – SOUser Mar 15 '19 at 23:04
  • @alterigel OK thanks. I almost thought that would not work. – SOUser Mar 15 '19 at 23:05
  • @alterigel The following problem caused me to say that I wanted to write my own `Function` class: I would like to save callbacks in a `std::vector` and to be able to remove these callbacks I would like to find and delete this function by value. Of course, I could save any callback under an id, but then the user would have to save this id for every callback in order to be able to delete the callback and I wanted to avoid that. – SOUser Mar 15 '19 at 23:22
  • 2
    Can't you use `typeid(mFunc)` for equality comparison? – Timo Mar 15 '19 at 23:45
  • 1
    You should keep each callback type in its own vector. – user207421 Mar 15 '19 at 23:56
  • @Timo Thanks, that would work and I would have hopes that the `typeid` will be recognized at compile time because I would only need to use it for functions and methods. I just hope that I will not regret it, because of `typeid` is usually advised against. – SOUser Mar 16 '19 at 00:08
  • @user207421 That's right, if I make a Vector for functions and one for methods, then even the virtual calls that I needed for my normal functions will fall away, and comparison would not be a problem anyway. The downside would be that I can not call the registered callbacks in turn, but in my case that should not cause any problems as far as I can imagine. Thank you! :) – SOUser Mar 16 '19 at 00:21
  • @user207421 I do not know what I thought in my answer above, "comparison would not be a problem anyway", as we have already said, you should not compare member function pointers. So the only solution would be `typeid` or the user would save an id / opaque object. – SOUser Mar 16 '19 at 03:01

0 Answers0