C++模板:部分模板规范和友元类

C++ Templates: Partial Template Specifications and Friend Classes

本文关键字:友元 模板 C++      更新时间:2023-10-16

是否有可能以某种方式使部分模板规范成为友元类? 即考虑您有以下模板类

template <class T> class X{
    T t;
};

现在您有部分专用化,例如,对于指针

template <class T> class X<T*>{
    T* t;
};

我想要实现的是,每个可能的X<T*>都是任何S的朋友类X<S>X<A*>应该是X<B>的朋友.

当然,我想到了 X 中一个常用的模板好友声明:

template <class T> class X{
    template <class S> friend class X<S*>;
}

但是,这不能编译,g++ 告诉我:

test4.cpp:34:15:错误:"template<class T> class X"的专用化必须出现在命名空间范围内

test4.cpp:34:21:错误:部分专用化"X<S*>"声明为"朋友"

这根本不可能还是有一些解决方法?

我问的原因是我需要X<T*>中的一个构造函数,它从任意X<S>创建这个类(S必须是T的子类型)。

代码如下所示:

template <class T> class X<T*>{
    T* t;
    template<class S>
    X(X<S> x) : t(&(x.t))  {} //Error, x.t is private
}

现在,编译器抱怨,当然,x.t在构造函数中不可见,因为它是私有的。这就是为什么我需要部分专业化的朋友类。

在C++中,您可以在四个级别上授予超出private的访问权限。

  • 完全public访问(参见PMR的答案)
  • 继承层次结构中的访问(protected,此处无关紧要)
  • 到基本模板friend(请参阅此答案)
  • 到非模板或完全专业化的friend(太弱,无法解决您的用例)

后两种友谊之间没有中间道路。

来自C++标准的§14.5.4:。

朋友声明不得声明部分专业化。

以下声明将允许您实现所需的内容。 它使您可以自由地从任何其他专业化访问模板的任何专业化,但仍然仅在X内。 它比你要求的稍微宽松一些。

template<class T> class X
{
    template<class Any> friend class X;
    public:
        ...
};

我们可以定义一个受 X 中定义的密钥保护的getter

#include <type_traits>
template <class T> class X{
  T t;
public:
  struct Key {
    template<typename S>
    Key(const X<S>&) {
      static_assert(std::is_pointer<S>::value, "Not a pointer");
    }
  };
  const T& get(Key) const { return t; }
  T& get(Key) { return t; }
};
template <class T> class X<T*> {
  T* t;
public:
  template<class S>
  X(X<S>& x) : t(&(x.get(typename X<S>::Key(*this))))  {}
};
int main()
{
  X<int> x1;
  X<int*> x2(x1);
  return 0;
}

这仍然有一些弱点。现在,每个拥有X<T*>的人都可以使用 get .但到现在为止,这已经如此混乱,以至于没有人愿意去意识到这一点。我会选择一个简单的公共获取者。