This question already has an answer here:
How to share protected members between C++ template classes?
(1 answer)
Closed 8 years ago.
This extremely minimal example will fail to compile because A<int> cannot access the private member i in A<double>
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
I cannot find the correct way to make those template instances friends.
template <class T>
class A {
template<class U>
friend class A;
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
Related
Here is the context.. I'm compiling with g++.
template<typename T>
class Array;
template<typename T>
int length(Array<T>& a);
template<typename T>
class Array
{
public:
//...
private:
T* a;
int b;
template<typename>
friend int length(Array<T>&);
};
template<typename T>
int length(Array<T>& a)
{
return a.b;
}
Is there a way to always declare "the corresponding friend length function" (i.e. length) if "the class is defined (i.e. Array)?
I thought maybe explicitely instantiate it like..
...
template<typename T>
class Array
{
public:
...
private:
...
template int length<T>(Array<T>&);
friend int length(Array<T>&);
};
...
NOTE: the above doesn't compile
Yes, you simply need to fix the declaration:
private:
T* a;
int b;
friend int length<>(Array<T>&);
It should be
template<typename T>
class Array
{
public:
//...
private:
T* a;
int b;
friend int length<>(Array&);
};
Demo
Your template<typename /*U*/> friend int length(Array<T>&); doesn't match outside template.
I think you can fix your code like this:
template<typename T>
class Array
{
public:
//...
int getB() { return b;};
private:
T* a;
int b;
template<typename>
friend int length(Array<T>&);
};
template<typename T>
int length(Array<T>& a)
{
return a.getB();
}
This extremely minimal example will fail to compile because A<int> cannot access the private member i in A<double>
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
I know that I can make all the template instances friends of each other (see: How to access private members of other template class instances?), but since I have only one method that requires the access (like in the example) I would prefer to limit the friendship to that method. Is this possible?
Yes, it's possible. Member functions can be designated as friends normally.
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
template <class F>
template <class U>
friend void A<F>::copy_i_from(const A<U> & a);
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
Live example (gcc one Ideone)
Note that unlike gcc, clang rejects the code. I cannot find anything in the standard that would make it invalid, though.
It seems that if you want to have a friend member function, the following won't work on clang:
template <class T>
class A {
int i;
public:
template <class U>
void copy_i_from( const A<U> & a ){
i = a.i;
}
template <class F>
template <class U> friend void A<F>::copy_i_from(const A<U> & a);
};
int main(void) {
A<int> ai;
A<double> ad;
ai.copy_i_from(ad);
return 0;
}
while it works on gcc.
The issue seems to be a clang's problem with representing friend class template for which the dependent name specifier cannot be resolved in the AST: http://llvm.org/klaus/clang/commit/8b0fa5241a0416fc50dfbb7e38f20e777f191848/ (still in trunk at the time of writing this).
Therefore you could go for the member function version above although it might not work on clang until this is figured out.
A plan-B solution is to have it a free templated friend function, although it might not be what you want (accepted by both cland and gcc):
#include <iostream>
using namespace std;
template <class T>
class A {
int i;
public:
template<class V, class U>
friend void copy_i_from(A<V>& t, const A<U> & a);
};
template<class V, class U>
void copy_i_from(A<V>& t, const A<U> & a){
t.i = a.i;
}
int main(void) {
A<int> ai;
A<double> ad;
copy_i_from(ai,ad);
return 0;
}
Example
I have a problem with two derived classes. I need that one receive the other as argument, but my code doesn't work (I semplified it to be more clear).
class:
#include<iostream>
#include<stdexcept>
using namespace std;
template <typename T> class A;
template <typename T> class B;
template <typename T> class C;
template <typename T> class A{
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A(){
throw logic_error("Error!");
}
~A(){
delete[] m[0];
delete[] m;
}
T say_elem(){
return m[0][0];
}
};
template <typename T> class B: public A<T>{
public:
B(int val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
};
template <typename T> class C: public A<T>{
public:
C(double val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
void renew(const B<T> &b){
if(A<T>::b.say_elem() > 0){
A<T>::m[0][0] = 1000;
}
}
};
main:
#include<iostream>
#include "class.cpp"
using namespace std;
int main(int argc, char **argv){
B <int> bbb(4);
C <double> ccc(5);
ccc.renew(bbb);
//no matching function for call to 'C<double>::renew(B<int>&)'
return 0;
}
the error is indicated above, what i need to do?
You are trying to call C<T>::renew(const B<T> &) with the wrong argument. What renew is expecting (in the call to the instance C<double>) is const B<double>&, not const B<int>&. They are two completely different classes. If you want to allow a B class with a different template parameter, templatize the function:
template<class U>
void renew(const B<U> &b) {
if(b.say_elem() > 0){
m[0][0] = 1000;
}
}
Ok, I combined Jefffrey's correct answer with my note from the comments to give a complete compiling and running code (which will throw logic_error("Error!") by the way, but this is off-topic).
#include<iostream>
#include<stdexcept>
using namespace std;
template <typename T> class A;
template <typename T> class B;
template <typename T> class C;
template <typename T> class A{
protected:
T **m;
void allocate_mem(T ***ptr){
*ptr = new T*[1];
(*ptr)[0] = new T[1];
}
public:
A(){
throw logic_error("Error!"); // remove this line for expected behavior
}
~A(){
delete[] m[0];
delete[] m;
}
T say_elem() const {
return m[0][0];
}
};
template <typename T> class B: public A<T>{
public:
B(int val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = val;
}
};
template <typename T> class C: public A<T>{
public:
C(double val){
A<T>::allocate_mem(& this->m);
A<T>::m[0][0] = 1;
}
template <typename U>
void renew(const B<U> &b){
if(b.A<U>::say_elem() > 0){
A<T>::m[0][0] = 1000;
}
}
};
int main(int argc, char **argv){
B <int> bbb(4);
C <double> ccc(5);
ccc.renew(bbb);
return 0;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to allow template function to have friend(-like) access?
How do I give function template Load friend access to class Foo?
The objective here is to restrict access to the constructor: only function template Load may construct.
CODE (please ignore memory leak)
class Foo {
Foo() { }
template<> friend Foo const& Load<Foo>(); // error here
};
template<typename T>
T const&
Load() { return *(new T); }
int main( int argc, char* argv[] )
{
Foo const& f = Load<Foo>();
}
This should work.
template<typename T> T const& Load() { return *(new T); }
class Foo {
Foo() { }
friend Foo const& Load<Foo>();
};
Doing it like this should work:
#include <iostream>
template <typename T>
const T&
load(void)
{
return *(new T);
}
class foo
{
private:
foo(void)
{
std::cout << "hello!" << std::endl;
}
template <typename T>
friend const T& load();
};
int
main(void)
{
const foo& f = load<foo>();
return 0;
}
I am trying to write an operator which converts between the differnt types of the same implementation. This is the sample code:
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};
int main(void)
{
A<int> a;
A<double> b = a;
return 0;
}
However, it gives the following error for line u.m_a = m_a;.
Error 2 error C2248: 'A::m_a' :
cannot access private member declared
in class
'A' d:\VC++\Vs8Console\Vs8Console\Vs8Console.cpp 30 Vs8Console
I understand the error is because A<U> is a totally different type from A<T>. Is there any simple way of solving this (may be using a friend?) other than providing setter and getter methods? I am using Visual studio 2008 if it matters.
VC10 accepts this:
template <class T = int>
class A
{
public:
template< typename U>
friend class A;
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
private:
int m_a;
};
You can declare the conversion function as friend
template <class T = int>
class A
{
public:
A() : m_a(0){}
template <class U>
operator A<U>()
{
A<U> u;
u.m_a = m_a;
return u;
}
template <class U> template<class V>
friend A<U>::operator A<V>();
private:
int m_a;
};
You could construct the A<U> with the int directly.