Link to home
Start Free TrialLog in
Avatar of List244
List244

asked on

ostream friend inside template

template <class T>
class Class1
{
public:
      class Class2
      {
      public:
      Class2()
      {
            SVal = 5;
      }
      friend ostream& operator <<(ostream& OStream, const Class2& Output);
      protected:
            T SVal;
      };
};
template <class T>
ostream& Class1<T>::Class2::operator <<(ostream& OStream, const Class2& Output)
{
      OStream << Output.SVal;
      return OStream;
}

Basically, what I am going for here is the ability to pass Class2 into a cout statement.  I can't seem
to get it working correctly, however.  Any help here would be great, thanks.
Avatar of rajeev_devin
rajeev_devin

Do this

template <class T>
class Class1
{
public:
      class Class2
      {
      public:
            Class2()
            {      
                  SVal = 5;
            }

            friend ostream& operator << (ostream& OStream, const Class2& Output);
            {
                  OStream << Output.SVal;
                  return OStream;
            }
      protected:
            T SVal;
      };
};
>> friend ostream& operator << (ostream& OStream, const Class2& Output);
remove semi-colon from end
As I know function of inner class cannot de defined outside
Avatar of List244

ASKER

I do not want to do it inside of the class, I want it outside. (Definition)
>> As I know function of inner class cannot de defined outside
I mean the templated classes.
>> I do not want to do it inside of the class, I want it outside. (Definition)
It is not possible
Avatar of List244

ASKER

Why is it not possible when I can do it with non-friend functions?
Else make it like
ostream& operator <<(ostream& OStream);

and define it outside like this
template <class T>
ostream& Class1<T>::Class2::operator <<(ostream& OStream)
{
     OStream << Output.SVal;
     return OStream;
}
ASKER CERTIFIED SOLUTION
Avatar of rajeev_devin
rajeev_devin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of List244

ASKER

So if it is not possible, is this correct?

#include <iostream>

using namespace std;

template <class T>
class Class1
{
public:
      class Class2
      {
      public:
      Class2()
      {
            SVal = 5;
      }
      friend ostream& operator <<(ostream& OStream, const Class2& Output)
      {
            OStream << Output.SVal;
            return OStream;
      }
      protected:
            T SVal;
      };
};
int main()
{
      Class1<int>::Class2 A;
      cout << A;
      return 0;
}

It runs fine, but when something like this works, then is removed and returns errors, it makes me skeptical as to whether or
not it is done correctly.
>> So if it is not possible, is this correct?
This is fine. It will work
Avatar of List244

ASKER

I know it works, but is it proper?

*Any other experts, your comments will be appreciated as well*

Can anyone provide perhaps the standard which states that friends can not be defined outside, or that
states it is undefined behavior?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of List244

ASKER

Alex, what compiler do you run?  I thought you would at least have to do something like:

ostream& Class1<T>::Class2::<<...

Anyway, that does not compile for me on VC++6 nor VC++ 2005 nor MinGW
>>>> that does not compile for me on VC++6

It compiles at VC6.

Did you exactly made a copy/paste of the above code snippet?

I used it in a test MFC application like that:

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
      //{{AFX_DATA_INIT(CAboutDlg)
      //}}AFX_DATA_INIT
    Class1<int>::Class2 ci;

    cout << ci << endl;
}

But MFC shouldn't matter. It must compile for any C++ project.

What error's did you get? Could you post your code again?

Regards, Alex
Avatar of List244

ASKER

#include <iostream>

using namespace std;

template <class T>
class Class1
{
public:
     class Class2
     {
     public:
     Class2()
     {
          SVal = 5;
     }
     friend ostream& operator <<(ostream& OStream, const Class2& Output);
     protected:
          T SVal;
     };
};

template <class T>
ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
{
     OStream << Output.SVal;
     return OStream;
}

int main()
{
      Class1<int>::Class2 A;
      cout << A;
      return 0;
}

VC++ 6 - error C2248: 'SVal' : cannot access protected member declared in class 'Class1<int>::Class2'
MinGW - expected unqualified-id before '&' token  |  expected `,' or `...' before '&' token  |  ISO C++ forbids declaration of `parameter' with no type

In function `std::ostream& operator<<(std::ostream&, int)':
  `Output' undeclared (first use this function)

VC++7 - error C2061: syntax error : identifier 'Class2'  |  error C2805: binary 'operator <<' has too few parameters
>>>> VC++ 6 - error C2248: 'SVal' : cannot access protected member declared in class 'Class1<int>::Class2'

That's a (known) bug in VC6 that - sometimes - friend declarations were ignored. I had same problems with friend operators some years ago.

My VC6 has all service packs included. I pasted your code to a *new* Win32 console project file - I named it 'friend' - and it compiles.

>>>> MinGW,  VC++7

These errors seem to be differently. What line do the errors refer to? Is it

     OStream << Output.SVal;

or

     cout << A;

?

Later - at home - I will be able to check the code under VC7.

Regards, Alex





Avatar of List244

ASKER

MinGW:
friend ostream& operator <<(ostream& OStream, const Class2& Output);  --
  warning: friend declaration `std::ostream& operator<<(std::ostream&, const Class1<T>::Class2&)' declares a non-template function

ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output) --
  expected unqualified-id before '&' token  |  expected `,' or `...' before '&' token  |  error: ISO C++ forbids declaration of `parameter' with no type

OStream << Output.SVal;
  `Output' undeclared (first use this function)

Vc++7:
ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
  warning C4346: 'Class1<T>::Class2' : dependent name is not a type
  error C2061: syntax error : identifier 'Class2'
Close of same function ( '}' )
  error C2805: binary 'operator <<' has too few parameters
Don't know much of MinGW but you might try to add the template specifier to the friend declaration:

   friend
   template <class T>
   ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);

or

   template <class T>
   friend
   ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);


VC7:

Here (and in MinGW) you could try to move the friend declaration to the Class1 body.

Regards, Alex
Avatar of List244

ASKER

No luck here.
That compiles under Vc7:

 #include <iostream>

using namespace std;

template <class T>
class Class1
{
public:
    class Class2
    {
    public:
        Class2()
        {
            SVal = 5;
        }
    protected:
        T SVal;
        template <class T>
            friend ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);
    };
};

template <class T>
ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
{
     OStream << Output.SVal;
     return OStream;
}

int main()
{
     Class1<int>::Class2 A;
     cout << A;
     return 0;
}

Regards, Alex
Avatar of List244

ASKER

Which version of .NET are you using? I am using 2005 express, and this does not compile.

friend ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);
  warning C4346: 'Class1<T>::Class2' : dependent name is not a type
  error C2061: syntax error : identifier 'Class2'
  error C2805: binary 'operator <<' has too few parameters

ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
  warning C4346: 'Class1<T>::Class2' : dependent name is not a type
  error C2061: syntax error : identifier 'Class2'

     OStream << Output.SVal;
     return OStream;
} //error C2805: binary 'operator <<' has too few parameters

Class1<int>::Class2 A;
  error C2079: 'A' uses undefined class 'Class1<T>::Class2'
Avatar of List244

ASKER

Increased points to 500
>>>> Which version of .NET are you using?

It's VS.NET 2003. Tomorrow (night) I could check VS.NET 2005 Pro.

>>>> warning C4346: 'Class1<T>::Class2' : dependent name is not a type

strange. Did you add the 'template' specifier?


>>>> Increased points to 500

You might add a new 20 points *pointer* question pointing to the question here.

Regards, Alex
 
Avatar of List244

ASKER

I did the code exactly how you posted it.
Avatar of Axter
List244,
Please post the new code, so that we can be sure what you're working with.
Avatar of List244

ASKER

The latest code I have tried is exactly that of which Itsmeandnobodyelse had said was working:

#include <iostream>

using namespace std;

template <class T>
class Class1
{
public:
    class Class2
    {
    public:
        Class2()
        {
            SVal = 5;
        }
    protected:
        T SVal;
        template <class T>
            friend ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);
    };
};

template <class T>
ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
{
     OStream << Output.SVal;
     return OStream;
}

int main()
{
     Class1<int>::Class2 A;
     cout << A;
     return 0;
}
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of List244

ASKER

Axter, I know that, but I was more hoping to get it out.  I like my definitions outside so that I have
a list of prototypes uninterrupted for both Class1 and Class2.
IMHO, it's easier to maintain code that consolidates implemenation and declaration, and it's also easier to read.

It would seem that the VC++ compiler is failing to recognized the template function outside of the class.  This is a problem that VC++ 6.0 had, and it was suppose to be fixed in VC++ 7.1/8.0.
Looks like there's still some left over bugs with it.
Avatar of List244

ASKER

I would think that if it SHOULD work that it would work in one of the compilers (MinGW,VC++6, or VC++7)
>>I would think that if it SHOULD work that it would work in one of the compilers (MinGW,VC++6, or VC++7)
It surely would not work in VC++ 6.0.

What do you get when you try it in MinGW?
Avatar of List244

ASKER

Axter, scroll up in the responses, I have listed each error and where they occur.
>>Axter, scroll up in the responses, I have listed each error and where they occur.

I did, and what I read was referring to the original code, which is incorrect.

What do you get with the new code on MinGW?
Avatar of List244

ASKER

18 Test..cpp declaration of `class T'
5 Test.cpp  shadows template parm `class T'
19 Test.cpp expected unqualified-id before '&' token
19 Test.cpp expected `,' or `...' before '&' token
19 Test.cpp ISO C++ forbids declaration of `parameter' with no type
24 Test.cpp expected unqualified-id before '&' token
24 Test.cpp expected `,' or `...' before '&' token
25 Test.cpp ISO C++ forbids declaration of `parameter' with no type

Test.cpp In function `std::ostream& operator<<(std::ostream&, int)':
  26 Test.cpp `Output' undeclared (first use this function)
Test.cpp In function `int main()':
  33 Test.cpp no match for 'operator<<' in 'std::cout << A'
I just tested it out, and I got the same results on DevC++.


When I get home, I'll try it on the Comeau compiler.
>>>> It surely would not work in VC++ 6.0.

As I told above the following code (Win32 console, no PCH)  compiles and runs under VC6 (Enterprise Edition, SP5) and XP (SP2).

#include <iostream>
using namespace std;

template <class T>
class Class1
{
public:
     class Class2
     {
     public:
     Class2()
     {
          SVal = 5;
     }
     friend ostream& operator <<(ostream& OStream, const Class2& Output);
     protected:
          T SVal;
     };
};

template <class T>
ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output)
{
     OStream << Output.SVal;
     return OStream;
}

int main()
{
     Class1<int>::Class2 A;
     cout << A;
     return 0;
}
// ------  end of code ----

At my private notebook (XP, SP2) I used VC7 2003 (no service packs). Here the above code compiled after I moved the friend declaration below the protected member and used the same function prototype as outside:

       template <class T>
       friend ostream& operator <<(ostream& OStream, const Class1<T>::Class2& Output);

This evening I'll check a freshly installed VS 2005 Pro (XP SP2).

Regards, Alex



Avatar of List244

ASKER

Itsmeandnobodyelse, I have tried that in VC++6 SP6 Enterprise with no success, also in 2005 Express and MinGW (Updated about a week ago)
>>As I told above the following code (Win32 console, no PCH)  compiles and runs under VC6 (Enterprise Edition, SP5) and XP (SP2).

I've tried it on VC++ 7.1, and it fails to compile.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of List244

ASKER

I am certain, I post my questions in generic form so that it is easier to get to the issue at hand.  My classes
are much larger and the outside must be a template.  The inside also must have a friend function to handle
iostreams << operator.  It COULD go inside, but really I am looking for a solution on how to get it outside.
I like to have my prototypes separate because for me it looks much cleaner.  I like to see my list
of functions and such uninterrupted.
I found the following in http://gcc.gnu.org/gcc-3.4/changes.html

----------------------------------------------------------------------------------------------------------
...
Friend declarations that refer to template specializations are rejected if the template has not already been declared. For example,
      template <typename T>
      class C {
        friend void f<> (C&);
      };
is rejected. You must first declare f as a template,

      template <typename T>
      void f(T);
In case of friend declarations, every name used in the friend declaration must be accessible at the point of that declaration. Previous versions of G++ used to be less strict about this and allowed friend declarations for private class members, for example. See the ISO C++ Standard Committee's defect report #209 for details.
Declaration of member functions of class templates as friends are supported. For example,
      template <typename T> struct A {
        void f();
      };
      class C {
        template <typename T> friend void A<T>::f();
      };
...
-----------------------------------------------------------------------------------

Applying to our case it might mean that operator<< needs to be declared forward *prior* to declaring it as friend (what does imply that both Class1 and Class2 need to be declared forwardly as well ... and arises the question whether it is it possible to make a forward declaration of  a sub class ???).

Unfortunately, the only compiler I have available *now* is a VC6 compiler that isn't compliant to any newer standard. So, I'll have to wait for tonight.

Regards, Alex

The following compiles under VS2005 Pro. The keyword 'typename' must be used when using a dependent type in a template definition. See http://msdn2.microsoft.com/en-us/library/tsx7wabs(VS.80,d=ide).aspx

#include <iostream>

using namespace std;

template <class T>
class Class1
{
public:
    class Class2
    {
    public:
        Class2()
        {
            SVal = 5;
        }
    protected:
        T SVal;
        template <class T>
        friend ostream& operator <<(ostream& OStream, const typename Class1<T>::Class2& Output);
    };
};

template <typename T>
ostream& operator <<(ostream& OStream, const typename Class1<T>::Class2& Output)
{
     OStream << Output.SVal;
     return OStream;
}

int main()
{
     Class1<int>::Class2 A;
     // cout << A;    // doesn't compile
     return 0;
}

Unfortunately, that doesn't help with the problem cause

   Class1<int>::Class2 A;
   cout << A;  

doesn't compile giving the following error:

.\friend.cpp(33) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Class1<T>::Class2' (or there is no acceptable conversion)

With other words, the compiler couldn't resolve the template function.

Any idea what might go wrong?

Regards, Alex
Avatar of List244

ASKER

Since we have been unable to get this functioning, I will split the points.