Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Personally I'd move the register_device() and unregister_device() functions outside of the VFS class entirely, perhaps to namespace scope.

Alternatively, there are other ways to leverage friendship and access control in C++. Here's one option:

    template <typename Registry>
    class DeviceManager;

    class Device {
        template<typename Registry> friend class DeviceManager;
        int y;
    };

    class VFS {
        friend struct DeviceManager<VFS>;
        int x;
    };

    template <typename Registry>
    struct DeviceManager {
        static void register_device (Registry& registry, Device& device) {
            registry.x = 1; // accessing privates
            device.y = 2;   // accessing privates
        }
    };

    int main() {
        VFS vfs;
        Device dev;
        DeviceManager<VFS>::register_device (vfs, dev);
    }
Here all DeviceManager<>'s can reach inside Devices, but only the VFS device manager can reach inside VFS.

This is also flexible. Remove 'static' and you get yourself a stateful mediator/manager. Add a variadic template register_devices_s_ member to Devicemanager and you've got yourself a convenience function for registering multiple devices (of heterogeneous types) without bloating the VFS API and, without runtime cost, and without losing type safety (by e.g. casting down to Device& from USBDevice&).



The thing is, there is no restriction on who calls DeviceManager<VFS>::register_device. main() is able to do it.

This doesn't seem so different from:

   class A { private: friend void foo(A &, B &); int x; };
   class B { private: friend void foo(A &, B &); int y; };

   void foo(A &a, B &b)
   {
      a.x = 1;
      b.y = 2;
   }
   
   int main() {
      A a; B b;
      foo(a, b);
   }
We've just obfuscated it a bit by using a template class with one function in it, and declaring that to be the friend instead of just a non-member function.


Yes, your version is what I mean by moving it to namespace scope, and it's probably what I'd do to start off with.

> there is no restriction on who calls DeviceManager<VFS>::register_device

Well, you can make it private inside DeviceManager and give the class its own friends :-))

Another benefit of my solution is that adding things to DeviceManager<VFS> doesn't require changing the VFS.h or Device.h headers at all. Anything that links these 2 classes is an entirely separate concern and very much in line with thinking in terms of models or concepts rather than types. What you want at the end of the day is an absolute bare minimum of member functions in any class.

To be honest, whatever the solution, the key is that having the Device class self-register to the VFS in its constructor (as in Andreas's blog post) is, imho, an anti-pattern and is what is really leading to this Badge mess.


Love this. I also felt that having an explicit `register` on a mediator like `DeviceManager` made much more sense for SOC, but this is really elegant. Maybe you should write and publish some C++ Idioms :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: