Интересный пример, когда определение friend T (где T — шаблонный параметр) имеет смысл:
template <class T> class Badge { friend T; Badge() { } };
Допустим, у нас есть какой-нибудь публичный метод, и предполагается, что круг его пользователей ограничен одним классом, например:
class VFS { ... public: void register_device(Device&); void unregister_device(Device&); };
Предполагается, что эти методы будут вызываться внутри конструкторов (и деструкторов) Device и нигде (и никем) больше. Но как закрепить наше ожидание на уровне API?
Распространенное решение — вынести (un)register_device в приватную часть, а Device объявить другом:
class VFS { private: friend class Device; void register_device(Device&); void unregister_device(Device&); };
И это действительно запрещает всем кроме Device обращаться к данным методам. Но это так же разрешает Device обращаться ко всем остальным членам VFS!
Выразить же желаемое наиболее четко и ясно нам помогает как раз таки класс Badge, приведенный в самом начале статьи: мы можем оставить методы (un)register_device публичными, но при этом сделать их первым аргументом значение Badge<Device>:
class VFS { ... public: void reg_Device(Badge<Device>, Device&); void unregister_device(Badge<Device>, Device&); };
Теперь чужак не может использовать эти методы, потому что он не может сконструировать Badge<Device>, а а сам Device может вызывать их где и как пожелает:
Device::Device() { VFS::instance().register_device({}, *this); }
