Search code examples
c++pointerspointer-to-member

Is there a way to declare a pointer to a particular method only?


I have a class:

class Car
{
    public:
        Car();
        ~Car();
        // nr indicates which particular door.
        void startEngie();
        void openDoor(int nr);
        void closeDoor(int nr); 
        void openWindow(int nr);
        void closeWindow(int nr);
        void turnOnAirConditioner(int vloume);
}

Now by void (Car::*action)(int) I declare a pointer named action to Car method. The problem is that many methods can be assigned to it: &Car::openDoor, &Car::closeDoor, &Car::openWindow, &Car::closeWindow, &Car::turnOnAirConditioner, but not &Car::startEngie.

I wonder if I am right: there is no way to declare a pointer to a particular method only. In other words: pointer type, which accept only a particular named function, can't be declared.


Solution

  • You can't define a type that is just "one specific value of this other type", for instance a type whose only existing value is exactly &Car::closeDoor.

    One thing you can do is reach for the Swiss army knife of programming - introduce a level of indirection - and define a type that represents one specific value by wrapping it inside something else.

    // Simplified Car
    class Car
    {
    public:
        void openDoor(int i) { std::cout << "open door\n"; }
        void closeWindow(int i) { std:cout << "close window\n"; }
    };
    
    using Fun = void (Car::*)(int);
    
    // A template for an immutable structure, so it 
    // can hold only one specific value; the template argument.
    template<Fun fun>
    struct CarOperation
    {
        const Fun f = fun;
    };
    
    // Now we can make one type for each operation
    using OpenDoor = CarOperation<&Car::openDoor>;
    using CloseWindow = CarOperation<&Car::closeWindow>;
    
    int main()
    {
        Car c;
        OpenDoor d;
        (c.*d.f)(1);
        CloseWindow e;
        (c.*e.f)(2);
    }
    

    The syntax is slightly unfortunate, because apparently the .* operator doesn't do any implicit conversion of its right operand.

    Of course, this is just a very roundabout and obfuscated way of simply calling the function indicated by the type.

    It would be more useful with a type that can hold a predetermined subset of the functions (like, say, DoorOperation or Opener types).
    You can probably build that using clever template programming, but I'm not a clever template programmer.