Discussion:
please help with friend function in nested class template
(too old to reply)
LiDongning
2009-09-10 19:59:17 UTC
Permalink
Hi,
I want to declare a function template as a friend in a nested class
template. The code is as follows.


template <class T>
class a1
{
public:
class a2
{
T att;
template <class T> friend const typename a1<T>::a2 operator +
(const typename a1<T>::a2&, const typename a1<T>::a2&);
};
};

template <class T>
const typename a1<T>::a2 operator + (const typename a1<T>::a2&, const
typename a1<T>::a2&)
{
return a1<T>::a2 xx;
}


int main()
{
a1<int> x;
a1<int>::a2 y;
y + y; //error! c2783
system("PAUSE");
return 0;
}

Complied in VC2008. Got error C2783. Tried couple of hours, just could
not make it work. Could somebody please help? Thanks very much!
Victor Bazarov
2009-09-10 20:18:34 UTC
Permalink
Post by LiDongning
I want to declare a function template as a friend in a nested class
template. The code is as follows.
template <class T>
class a1
{
class a2
{
T att;
template <class T> friend const typename a1<T>::a2 operator +
. ^^^^^
BTW, top-level const is ignored.
Post by LiDongning
(const typename a1<T>::a2&, const typename a1<T>::a2&);
In order for a function to be declared a friend, it has to be declared
first. A function needs to be declared outside (before) the class a1
template. And since you're trying to get it to take 'a1's nested class
as its argument, and there is no forward-declaration of members, you're SOL.
Post by LiDongning
};
};
template <class T>
const typename a1<T>::a2 operator + (const typename a1<T>::a2&, const
typename a1<T>::a2&)
{
return a1<T>::a2 xx;
Huh? Consider posting real code with which you have the problem.
Post by LiDongning
}
int main()
{
a1<int> x;
a1<int>::a2 y;
y + y; //error! c2783
system("PAUSE");
return 0;
}
Complied in VC2008. Got error C2783. Tried couple of hours, just could
not make it work. Could somebody please help? Thanks very much!
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
LiDongning
2009-09-10 20:28:51 UTC
Permalink
forward declaration is not the problem. When a function is declared as
a friend in a class declaration, the function is declared as well.
The following codes demonstrate the situation.

#include <iostream>
using namespace std;

class x
{
int y;

public:
x():y(5) {}
friend void fun(const x&); //fun is declared at the same time.
};

void fun(const x& x1)
{
cout<<x1.y<<endl;
}

int main()
{
x x1;
fun(x1);
system("PAUSE");
return 0;
}
Post by LiDongning
I want to declare a function template as a friend in a nested class
template. The code is as follows.
template <class T>
class a1
{
      class a2
      {
      T att;
      template <class T> friend const typename a1<T>::a2 operator +
.                                 ^^^^^
BTW, top-level const is ignored.
Post by LiDongning
(const typename a1<T>::a2&, const typename a1<T>::a2&);
In order for a function to be declared a friend, it has to be declared
first.  A function needs to be declared outside (before) the class a1
template.  And since you're trying to get it to take 'a1's nested class
as its argument, and there is no forward-declaration of members, you're SOL.
Post by LiDongning
      };
};
template <class T>
const typename a1<T>::a2 operator + (const typename a1<T>::a2&, const
typename a1<T>::a2&)
{
      return a1<T>::a2 xx;
Huh?  Consider posting real code with which you have the problem.
Post by LiDongning
}
int main()
{
    a1<int> x;
    a1<int>::a2 y;
    y + y;   //error! c2783
    system("PAUSE");
    return 0;
}
Complied in VC2008. Got error C2783. Tried couple of hours, just could
not make it work. Could somebody please help? Thanks very much!
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Igor Tandetnik
2009-09-10 21:46:42 UTC
Permalink
Post by LiDongning
I want to declare a function template as a friend in a nested class
template. The code is as follows.
template <class T>
class a1
{
class a2
{
T att;
template <class T> friend const typename a1<T>::a2 operator +
(const typename a1<T>::a2&, const typename a1<T>::a2&);
};
};
template <class T>
const typename a1<T>::a2 operator + (const typename a1<T>::a2&, const
typename a1<T>::a2&)
{
return a1<T>::a2 xx;
}
int main()
{
a1<int> x;
a1<int>::a2 y;
y + y; //error! c2783
system("PAUSE");
return 0;
}
Complied in VC2008. Got error C2783.
Friend declaration is a red herring. The real problem is that, in
operator+ invocation, T is in a non-deducible context. Consider:

template <typename T>
struct Outer {
struct Inner {};
};

template <typename T>
void f(const typename Outer<T>::Inner& x) {}

int main() {
Outer<int>::Inner y;
f(y); // error here
return 0;
}

In f(y) call, the compiler cannot deduce that T==int. For all it knows,
you have something like this somewhere in your program:

template<>
struct Outer<long> {
typedef Outer<int>::Inner Inner;
};

Now Outer<int>::Inner and Outer<long>::Inner both name the same type.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
LiDongning
2009-09-11 20:26:12 UTC
Permalink
Exactly. I just figured that I can make the code work if I use
following form to call the "+" operator

operator+<int>(y,y);

But this just lost my intention to use operator overloading -- to
make the code simple

Anyway, thanks very much for the help.

DN
Post by Igor Tandetnik
Post by LiDongning
I want to declare a function template as a friend in a nested class
template. The code is as follows.
template <class T>
class a1
{
     class a2
     {
     T att;
     template <class T> friend const typename a1<T>::a2 operator +
(const typename a1<T>::a2&, const typename a1<T>::a2&);
     };
};
template <class T>
const typename a1<T>::a2 operator + (const typename a1<T>::a2&, const
typename a1<T>::a2&)
{
     return a1<T>::a2 xx;
}
int main()
{
   a1<int> x;
   a1<int>::a2 y;
   y + y;   //error! c2783
   system("PAUSE");
   return 0;
}
Complied in VC2008. Got error C2783.
Friend declaration is a red herring. The real problem is that, in
template <typename T>
struct Outer {
  struct Inner {};
};
template <typename T>
void f(const typename Outer<T>::Inner& x) {}
int main() {
  Outer<int>::Inner y;
  f(y);  // error here
  return  0;
}
In f(y) call, the compiler cannot deduce that T==int. For all it knows,
template<>
struct Outer<long> {
  typedef Outer<int>::Inner Inner;
};
Now Outer<int>::Inner and Outer<long>::Inner both name the same type.
--
With best wishes,
    Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925- Hide quoted text -
- Show quoted text -
Tamas Demjen
2009-09-11 21:39:08 UTC
Permalink
Post by Igor Tandetnik
Friend declaration is a red herring. The real problem is that, in
operator+ invocation, T is in a non-deducible context.
I think what he's trying to achieve is this:

template <class T>
class a1
{
public:
class a2
{
friend typename a1<T>::a2 operator+(
const typename a1<T>::a2&,
const typename a1<T>::a2&)
{
return a1<T>::a2(); // TODO implement it for real
}
};
};

Only without defining operator+ inline. He wants to implement it outside
of the class.

To the original poster: Is there a reason why you can't you define
operator+ inline?

How about this:

template <class T>
class a1
{
public:
class a2
{
static typename a1<T>::a2 add(
const typename a1<T>::a2& lhs,
const typename a1<T>::a2& rhs);

friend typename a1<T>::a2 operator+(
const typename a1<T>::a2& lhs,
const typename a1<T>::a2& rhs)
{
return add(lhs, rhs);
}
};
};

template <class T>
typename a1<T>::a2 a1<T>::a2::add(
const typename a1<T>::a2& lhs,
const typename a1<T>::a2& rhs)
{
return a1<T>::a2(); // TODO implement it for real
}

int main()
{
a1<int>::a2 y;
y + y;
return 0;
}

This way you can make the actual implementation outside of the class.
But it must still go to the header file, not to the .cpp.

Tom

Loading...