I'm trying to access protected variables of a template class with different template parameters. A friend declaration with template parameters is giving the following error:
multiple template parameter lists are not allowed
My code is
template<class O_, class P_>
class MyClass {
//multiple template parameter lists are not allowed
template<class R_> friend class MyClass<R_, P_>
//syntax error: template<
friend template<class R_> class MyClass<R_, P_>
public:
template<class R_>
ACopyConstructor(MyClass<R_, P_> &myclass) :
SomeVariable(myclass.SomeVariable)
{ }
protected:
O_ SomeVariable;
};
If I remove the protection and friend declaration it works.
From the standard: 14.5.3/9 [temp.friend], "A friend template shall not be declared partial specializations.", so you can only 'befriend' all instantiations of a class template or specific full specializations.
In your case, as you want to be friends with instantiations with one free template parameter, you need to declare the class template as a friend.
e.g.
template< class A, class B > friend class MyClass;
The following seems to be working, effectively declaring all MyClass types to be friend with each other.
template<class O_, class P_>
class MyClass {
template<class R_, class P_> friend class MyClass;
public:
template<class R_>
ACopyConstructor(MyClass<R_, P_> &myclass) :
SomeVariable(myclass.SomeVariable)
{ }
protected:
O_ SomeVariable;
};
Related
This question already has answers here:
Compiler error in declaring template friend class within a template class
(2 answers)
Class template with template class friend, what's really going on here?
(5 answers)
Closed 11 days ago.
code of my two template class
Errors
Ive tried using "friend class" declaration instead of "friend".
replacing "friend" with "friend class"
The errors is caused by creating a Mydeque object within main.
template <typename T>
class Mydeque
{
private:
T* data;
int cap, sz;
friend class Iterator<T>;
public:
Mydeque(): cap(0), sz(0) //Constructor
{
//do nothing
}
};
template<class T>
class Iterator
{
public:
private:
size_t current;
Mydeque<T>* container;
friend class Mydeque<T>;
};
You can either forward declare the class template and then befriend it or add a separate template clause as shown below:
//forward declaration
template<typename T> class Iterator;
template <typename T>
class Mydeque
{
private:
friend class Iterator<T>;
};
template<class T>
class Iterator
{
friend class Mydeque<T>;
};
demo
Method 2
In this case, instead of forward declaring the befriend class template separaterly, we add a separate template clause so that all instantiations of that template are friends.
template <typename T>
class Mydeque
{
template<typename U> friend class Iterator;
};
template<class T>
class Iterator
{
friend class Mydeque<T>;
};
Let's say I have to following hierarchy:
template<class T> class Base {
protected:
T container;
};
template<class T> class Derived1 : public Base<T> {
public:
void f1() {
/* Does stuff with Base<T>::container */
}
};
template<class T> class Derived2 : public Base<T> {
public:
void f2() {
/* Does stuff with Base<T>::container */
}
};
Now I want an independent Class (not derived from Base) that can access the Base<T>::container directly from Base or any Derived class. I read about template friend classes and it seems to be the solution to my problem but I couldn't figure out the syntax yet.
I am looking for something like:
template<class T> class Foo{
template<T> friend class Base<T>; // <-- this does not work
public:
size_t bar(const Base<T> &b) const{
return b.container.size();
}
};
Derived1<std::vector<int> > d;
d.f1();
Foo<std::vector<int> > foo;
size_t s = foo.bar()
The friend class line causes an error: specialization of ‘template<class T> class Base’ must appear at namespace scope template<T> friend class Base<T> and the member variable container is still not accessible.
A couple of issues:
Just as you don't put a <T> after the class name when defining a class template:
template <class T> class X<T> { ... }; // WRONG
template <class T> class X { ... }; // RIGHT
you shouldn't put it after the class name when declaring a class template, whether in a forward declaration or friend declaration:
template <class T> class X<T>; // WRONG
template <class T> class X; // RIGHT - declares the template exists
template <class T> friend class X<T>; // WRONG
template <class T> friend class X; // RIGHT - says all specializations of X are friends
(Unless you're creating a class template partial specialization. For example, if class template X is already declared, then template <class T> class X<T*> { ... }; defines a partial specialization that will be used instead of the primary template when the template argument is a pointer.)
And you have the friend declaration backwards: it needs to appear inside the class with the non-public member(s), and name the other class(es) which are allowed to use the members. (If it worked the other way around, then any new class could gain access to any other class's private and protected members, without the permission of the owning class!)
So you would need:
template <class T> class Foo;
template<class T> class Base {
template <class U> friend class Foo;
protected:
T container;
};
The forward declaration of Foo is sometimes not needed, but I think it makes things clearer, and it can avoid gotchas when things start getting more complicated with namespaces, nested classes, etc.
Only Base can say Foo is its friend.
template<typename T> friend class Foo; // every Foo<T> is a friend of Base
lets say that I have 2 template classes, A and B. If I want to make B a friend of A, what would I say ?
class<template T>
class A
{
public:
friend class B<T>; // ???
};
class<template T>
class B
{
};
To use a symbol, it must be declared or defined, this is the same in template. You need to forward declare template B. Also your syntax(class<template T>) to declare template class is not valid, it should be template <class T>.
This should work:
template <typename T> // typename can be replaced with class
class B;
template <typename T>
class A
{
public:
friend class B<T>;
};
template <typename T>
class B
{
};
The following is a simple c++ program that compiles with my MinGW compiler, and executes as expected:
#include <iostream>
template <class T> class A {
T a;
template <class U> friend class B;
public:
A<T> (T t) : a(t) {}
};
template <class T> class B {
A<T> aa;
public:
B<T> (T t) : aa(t) {}
T getT() const {return aa.a;}
};
int main() {
B<int> b(5);
std::cout << "> " << b.getT() << std::endl;
}
Since B<T>::getT() accesses the private A<T>::a member, A<T> makes B<T> a friend with template <class U> friend class B; line.
Unfortunately, I don't know why this line needs to be written like this. Intuitively, I would have expected something like friend class B<T>, yet, this doesn't compile.
The meaning of the newly introduced U is unclear as well, since A's and B's dependant type is T in both cases.
So, in short, I'd appreciate any light on how the syntax for this line is derived or deduced.
There are many different permutations of friendship and templates.
Your present code makes any template specialization of B into a friend for A<T>, so for example B<char> is a friend of A<int>.
If you only wanted to make the matching A<T> a friend, you would say it like this:
template <typename> class B; // forward declare above!
template <typename T>
class A
{
// ...
friend class B<T>;
};
IMHO, friend class B<T>; would have worked had you inserted a forward declaration
template<class T> class B;
before that of class A<T>.
The template <class U> friend class B; makes every class B<U> a friend, not just class B<T>.
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.
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.