?
Solved

ostream friend inside template

Posted on 2006-05-21
44
Medium Priority
?
1,268 Views
Last Modified: 2008-01-09
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.
0
Comment
Question by:List244
  • 19
  • 9
  • 8
  • +2
44 Comments
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731339
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;
      };
};
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731343
>> friend ostream& operator << (ostream& OStream, const Class2& Output);
remove semi-colon from end
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731347
As I know function of inner class cannot de defined outside
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 8

Author Comment

by:List244
ID: 16731348
I do not want to do it inside of the class, I want it outside. (Definition)
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731356
>> As I know function of inner class cannot de defined outside
I mean the templated classes.
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731361
>> I do not want to do it inside of the class, I want it outside. (Definition)
It is not possible
0
 
LVL 8

Author Comment

by:List244
ID: 16731362
Why is it not possible when I can do it with non-friend functions?
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731367
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;
}
0
 
LVL 12

Accepted Solution

by:
rajeev_devin earned 800 total points
ID: 16731375
with friend its not possible
0
 
LVL 8

Author Comment

by:List244
ID: 16731386
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.
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 16731749
>> So if it is not possible, is this correct?
This is fine. It will work
0
 
LVL 8

Author Comment

by:List244
ID: 16731762
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?
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 400 total points
ID: 16733256
Try that:

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


That compiles at my system though I don't know whether there is any senseful purpose for that. Normally inner classes cannot defined outside of the outer class.

Regards, Alex


0
 
LVL 8

Author Comment

by:List244
ID: 16734536
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
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16735287
>>>> 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
0
 
LVL 8

Author Comment

by:List244
ID: 16735558
#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
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16735960
>>>> 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





0
 
LVL 8

Author Comment

by:List244
ID: 16736073
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
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16736350
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
0
 
LVL 8

Author Comment

by:List244
ID: 16737210
No luck here.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16737755
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
0
 
LVL 8

Author Comment

by:List244
ID: 16737824
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'
0
 
LVL 8

Author Comment

by:List244
ID: 16737826
Increased points to 500
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16739942
>>>> 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
 
0
 
LVL 8

Author Comment

by:List244
ID: 16743026
I did the code exactly how you posted it.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16744391
List244,
Please post the new code, so that we can be sure what you're working with.
0
 
LVL 8

Author Comment

by:List244
ID: 16744422
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;
}
0
 
LVL 30

Assisted Solution

by:Axter
Axter earned 400 total points
ID: 16744892
First rule of thumb, is to keep it simple.
I always recommend keeping template functions inside the template class declaration.
The following should compile and run with no problem:

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

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

Author Comment

by:List244
ID: 16744912
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.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16744955
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.
0
 
LVL 8

Author Comment

by:List244
ID: 16744990
I would think that if it SHOULD work that it would work in one of the compilers (MinGW,VC++6, or VC++7)
0
 
LVL 30

Expert Comment

by:Axter
ID: 16745051
>>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?
0
 
LVL 8

Author Comment

by:List244
ID: 16745059
Axter, scroll up in the responses, I have listed each error and where they occur.
0
 
LVL 30

Expert Comment

by:Axter
ID: 16745078
>>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?
0
 
LVL 8

Author Comment

by:List244
ID: 16745137
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'
0
 
LVL 30

Expert Comment

by:Axter
ID: 16745495
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.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16748666
>>>> 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



0
 
LVL 8

Author Comment

by:List244
ID: 16751610
Itsmeandnobodyelse, I have tried that in VC++6 SP6 Enterprise with no success, also in 2005 Express and MinGW (Updated about a week ago)
0
 
LVL 30

Expert Comment

by:Axter
ID: 16751759
>>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.
0
 
LVL 5

Assisted Solution

by:dennis_george
dennis_george earned 400 total points
ID: 16752746
Do you really want the outer class to be a template class because you are only inner class as a generic class....
try the following code......

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

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

Author Comment

by:List244
ID: 16752774
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.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16753369
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

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 16760136
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
0
 
LVL 8

Author Comment

by:List244
ID: 16921433
Since we have been unable to get this functioning, I will split the points.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Article by: evilrix
Looking for a way to avoid searching through large data sets for data that doesn't exist? A Bloom Filter might be what you need. This data structure is a probabilistic filter that allows you to avoid unnecessary searches when you know the data defin…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question