C++ Templates: Partial Template Specifications and Friend Classes

is it possible to somehow make a partial template specification a friend class? Ie consider you have the following template class

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

Now you have partial specializations, for example, for pointers

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

What I want to accomplish is that every possible X<T*> is a friend class of X<S> for ANY S . Ie X<A*> should be a friend of X<B> .

Of course, I thought about a usual template friend declaration in X:

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

However, this does not compile, g++ tells me this:

test4.cpp:34:15: error: specialization of ' template<class T> class X ' must appear at namespace scope

test4.cpp:34:21: error: partial specialization ' X<S*> ' declared 'friend'

Is this not possible at all or is there some workaround?

The reason why I am asking is that I need a constructor in X<T*> that creates this class from an arbitrary X<S> ( S must be a subtype of T ).

The code looks like this:

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

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

Now, the compiler complains, of course, that xt is not visibile in the constructor since it is private. This is why I need a partial specialization friend class.


In C++, you can grant access beyond private on four levels.

  • completely public access (see pmr's answer)
  • access within inheritance hierarchy ( protected , irrelevant here)
  • to a base template friend (see this answer)
  • to a non-template or fully specialized friend (too weak to solve your use case)
  • There is no middle way between the two latter kinds of friendship.

    From §14.5.4 of the C++ standard:.

    Friend declarations shall not declare partial specializations.

    The following declaration will allow you to implement what you need. It gives you a free hand to access any specialization of your template from any other specialization, but still only within X . It is slightly more permissive than what you asked for.

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

    We can define a getter protected by a key defined in X.

    #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;
    }
    

    This still has some weakness. Everybody with an X<T*> can now use get . But this is so obfuscated by now, that no one is goiing to realize that. I'd choose a simple public getter.

    链接地址: http://www.djcxy.com/p/60596.html

    上一篇: objc有什么区别?

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