问题
is it possible to somehow make a partial template specification a friend class? I.e. 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
. I.e. 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 x.t
is not visibile in the constructor since it is private. This is why I need a partial specialization friend class.
回答1:
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:
...
};
回答2:
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.
来源:https://stackoverflow.com/questions/11041274/c-templates-partial-template-specifications-and-friend-classes