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

时间:2012-06-14 21:00:51

标签: c++ templates template-specialization partial-specialization friend-class

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

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

现在你有部分专业化,例如指针

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

我想要完成的是,每个可能的X<T*>都是X<S>的朋友类,适用于任何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在构造函数中是不可见的,因为它是私有的。这就是为什么我需要一个部分专业化的朋友类。

2 个答案:

答案 0 :(得分:3)

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

  • 完全public访问权限(请参阅pmr的回答)
  • 在继承层次结构(protected内访问,此处无关紧要)
  • 到基本模板friend(请参阅此答案)
  • 到非模板或完全专业的friend(太弱而无法解决您的使用案例)

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

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

  

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

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

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

答案 1 :(得分:1)

我们可以定义受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。但是现在这种情况很混乱,没有人会这么做 认识到。我会选择一个简单的公共吸气剂。