我们可以添加一个基于模板参数的朋友类吗

Can we add a friend class based on template parameter?

本文关键字:参数 于模板 朋友 一个 添加 我们      更新时间:2023-10-16

我想知道以下棘手的情况是否可能:

假设我有一个模板类template <typename DTYPE> class A{};,其中DTYPE应该是uint8_tuint16_t等中的一个。我想向A添加一个朋友类,但这个朋友类对于每个DTYPE备选方案都不同。此外,假设不同DTYPE值的朋友类不是另一个模板类的实例化,而是独立的类。

有办法做到吗?

您可以添加模板"代理"类FriendOfA,并将其专门化为您需要的任何类型:

// actual friends
class FriendUint8 {};
class FriendUint16 {};
template<typename T> struct FriendOfA;
template<>
struct FriendOfA<uint8_t> {
    typedef FriendUint8 type;
};
template<>
struct FriendOfA<uint16_t> {
    typedef FriendUint16 type;
};
// optional helper
template <typename T>
using FriendOfA_t = typename FriendOfA<T>::type;
template<class T>
class A {
    friend typename FriendOfA<T>::type;
    // or simply
    friend FriendOfA_t<T>;
};

我相信你正在寻找这样的东西:

#include <iostream>
struct BaseFriend 
{
    template <typename T>
    void boo(const T& t) { t.foo(); }   
};
struct BaseFriendProxy
{
    template <typename T>
    void boo(const T& t) { std::cout << "Proxy: "; t.foo(); }   
};
template <typename TType> 
struct Friend ;
template <>
struct Friend<int> {
    using T = BaseFriend;
};
template <>
struct Friend<char> {
    using T = BaseFriendProxy;
};
template <typename DTYPE> 
class A
{
private:
    friend typename Friend<DTYPE>::T;
    void foo() const 
    { std::cout << "A::foo()" << std::endl; }    
};
int main()
{
   A<int> a;
   BaseFriend bf1;
   bf1.boo(a);
   A<char> b;
   BaseFriendProxy bf2;
   bf2.boo(b);
   return 0;
}

但这只适用于C++11:在C++03 中不能将friend class ...typename X::Y组合起来

当然可以,专门化你的模板并添加你想要的任何朋友类:

#include <iostream>
using namespace std;
class base {
 public:
    virtual int getValue() = 0;
};
class friend1 {
    public:
    base* ptr;
    int getValue() {
        return ptr->getValue();
    }
};
class friend2 {
    public:
    base* ptr;
    int getValue() {
        return ptr->getValue();
    }
};
template <typename DTYPE> class A :  public base{
    public:
    A() { data = 42; }
    // No friends
    private:
    int data;
    int getValue() {
        return data;
    }
};
template <> class A<char> :  public base{
    public:
    A() { data = 44; }
    friend class friend1;
    private:
    int data;
    int getValue() {
        return data;
    }
};
template <> class A<bool> :  public base{
    public:
    A() { data = 45; }
    friend class friend2;
    private:
    int data;
    int getValue() {
        return data;
    }
};

int main()
{
    A<char> obj1;
    friend1 friend_of_obj1;
    friend_of_obj1.ptr = &obj1;
    cout << friend_of_obj1.getValue() << endl;
    A<bool> obj2;
    friend2 friend_of_obj2;
    friend_of_obj2.ptr = &obj2;
    cout << friend_of_obj2.getValue();
}

http://ideone.com/hM9x0y

是的,朋友可以基于模板。例如

template <typename DTYPE>
struct Friend;
template <class DTYPE>
class A {
    friend struct Friend<DTYPE>;
};

对于您希望支持的类A的每种类型DTYPE(根据实现不同),您可以专门处理Friend,例如;

template<>
struct Friend<uint8_t> {
    // ...
};

一个基本的工作样本:

#include <cstdint>
using namespace std;
template<typename T>
struct Friend;
template <class T>
class A {
    friend struct Friend<T>;
    int i = 0;    
};
template<>
struct Friend<uint8_t> {
    void method() {
        A<uint8_t> a;
        a.i = 8;
    }
};
template<>
struct Friend<uint16_t> {
    void method() {
        A<uint16_t> a;
        //A<uint8_t> b; // fails to compile
        a.i = 16;
    }
};
int main()
{
    A<uint8_t> a;
    Friend<uint8_t> f;
    f.method();
}