Интересный пример, когда определение 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);
}