Why do I get "..::b is private within this context" - c++

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();
}

Related

Declare many functions as friends of a class

How to conveniently declare many template functions as friend function of a template class?
Example:
template <typename T>
void funct1(MyClass<T> & A); //1.forward declaration.
template <typename T>
class MyClass{
protected:
T a;
friend funct1(MyClass<T> & A); //2.declare friend
}
template <typename T>
void funct1(MyClass<T> & A){ //3.actual implementation
++A.a;
}
step 1,2,3 get repeated for each of the many functions....
Is it possible to group all these function into something, then declare everything in that something are friends of the template class?
How about A friend class, all the functions can go into that one friend class:
#include <iostream>
using namespace std;
template <typename T>
class MyFriend;
template <typename T>
class MyClass{
protected:
T a;
public:
MyClass(T _a):a(_a) {}
friend MyFriend<T>;
};
template <typename T>
class MyFriend {
public:
void funct1(MyClass<T> &A) {
++A.a;
cout << "A.a: " << A.a << endl;
}
void funct2(MyClass<T> &B) {
B.a += 2;
cout << "A.a: " << B.a << endl;
}
};
int main() {
MyClass<int> myclass(0);
MyFriend<int> myfriend;
myfriend.funct1(myclass);
myfriend.funct2(myclass);
return 0;
}
Yes! You can make them static member functions of a class, and make that class a friend.
template <typename T>
class MyClass{
protected:
T a;
friend class MyFunctions;
}

How to let a method access private members of other template class instances?

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

c++ derived classes, one is the argument of the other

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

Conversion between different template instantiation of the same template

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.

Friend function and templates

My question is related to this question.
#include<iostream>
template< typename T >
class T1 {
public:
T i;
void display()
{
std::cout<<i<<"\n"<<j<<"\n"<<k;
}
protected:
T j;
private:
T k;
friend void Test( T1 &obj);
};
template<typename T>
void Test(T1<T> &obj)
{
T a=T();
obj.i=a;
obj.j=a;
obj.k=a;
}
int main()
{
T1<int>a;
Test(a);
a.display();
}
Why doesn't the above code compile?
friend void Test( T1 &obj); declares a non template function.
Declare it as a template.
Try this :
....
private:
T k;
template<typename U>
friend void Test( T1<U> &obj);
};