Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload operator<< for nested class template

I have the following setup:

template< class T >
struct Foo {

  struct Bar {
    Bar ( const T &t ) : otherT_( t ) {}

    T otherT_;
  };

  Foo ( const T &t ) : myT_( t ) {}

  T myT_;
};

Now, I want to make instances of Foo< T >::Bar streamable to std::cout and friends. I tried this:

template< class T >
std::ostream& operator<< ( std::ostream &os, 
                           const typename Foo< T >::Bar &bar ) {
  os << "<bar: " << bar.otherT_ << ">";
  return os;
}

But the following code does not compile:

  Foo< int > foo( 5 );
  Foo< int >::Bar bar( 7 );

  std::cout << bar << std::endl;

I guess that the compiler is not able to deduce the type T or something. Is there a way to make such instances of the nested class behave well with operator<<?

Thank you!

like image 682
Sh4pe Avatar asked Sep 16 '13 08:09

Sh4pe


3 Answers

Yep, the easy way is to put operator<< inside Bar:

struct Bar {
  Bar ( const T &t ) : otherT_( t ) {}

  T otherT_;

  friend std::ostream& operator<< ( std::ostream &os, const Bar &bar ) 
  {
    os << "<bar: " << bar.otherT_ << ">";
    return os;
  }
};

I am digging the other way ...

like image 161
Raffi Avatar answered Oct 07 '22 07:10

Raffi


Workaround - define operator<< as a friend inside Bar's definition:

template< class T >
struct Foo {

  struct Bar {
    Bar ( const T &t ) : otherT_( t ) {}

    T otherT_;

    friend std::ostream& operator<< ( std::ostream &os, const Bar &bar )
    {
      os << "<bar: " << bar.otherT_ << ">";
      return os;
    }

  };

  Foo ( const T &t ) : myT_( t ) {}

  T myT_;
};

The problem with your approach is, as KerrekSB said in comments, that T could not be deduced. There are possibly infinitely many T for Foo<T>::Bar, each of which could result in a different type, too.

like image 38
jrok Avatar answered Oct 07 '22 05:10

jrok


The compiler cannot deduce T, however, when you make it a friend it finds it via ADL.

I've modified the code to the following:

#include <iostream>
using namespace std;

template< class T >
struct Foo {

struct Bar {
Bar ( const T &t ) : otherT_( t ) {}

T otherT_;
friend std::ostream& operator << (std::ostream& os, const Bar &bar )
{ return os; }
};

Foo ( const T &t ) : myT_( t ) {}


T myT_;
};

int main() {
Foo< int > foo( 5 );
Foo< int >::Bar bar( 7 );

std::cout << bar << std::endl;
return 0;
}
like image 27
Werner Erasmus Avatar answered Oct 07 '22 05:10

Werner Erasmus