Generic ostream operator<<?

G

Gerhard Fiedler

Victor said:
Well, you defined a very broad operator<<. It will match pretty much
any type that allows binding to a const ref. Considering that VC++
doesn't let you have default template arguments for function
templates (based on your attempt to get Luca's solution to build), I
am not sure how you'd be able to narrow down the set of types to
which your templated op<< applies without using inheritance. Here is
a suggestion (it does require editing of your types): [...]

Thanks. I keep this in mind, but it doesn't look much better than
explicitly declaring a friendly global operator<<().

I'm still working on getting my original approach to work (please see my
other post in this thread if you're interested). I'm not yet
understanding well enough how I can limit the matching.

Gerhard
 
C

cartec69

I'm still working on getting my original approach to work (please see my
other post in this thread if you're interested). I'm not yet
understanding well enough how I can limit the matching.

See http://stackoverflow.com/questions/...c-template-to-check-for-a-functions-existence for a very good discussion of how to detect a member function. Applying the principles discussed there to your program:

#include <iostream>
#include <type_traits>

template <typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template <typename C> static yes& test( decltype(&C::print) );
template <typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template < class Printable >
typename std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream &stream ) const { stream << str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout << MyClass( "bar" ) << std::endl;
}

If you have types in your codebase that you want to exclude - say they have a print member that serves some other purpose - you can do so with a specialization:

template <>
class is_printable<Foo>
{ public: static const bool value = false; };
 
G

Gerhard Fiedler

I'm still working on getting my original approach to work (please see
my other post in this thread if you're interested). I'm not yet
understanding well enough how I can limit the matching.

See http://stackoverflow.com/questions/...c-template-to-check-for-a-functions-existence
for a very good discussion of how to detect a member function.
Applying the principles discussed there to your program:

#include <iostream>
#include <type_traits>

template <typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template <typename C> static yes& test( decltype(&C::print) );
template <typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template < class Printable >
typename std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream &stream ) const { stream << str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout << MyClass( "bar" ) << std::endl;
}

If you have types in your codebase that you want to exclude - say they
have a print member that serves some other purpose - you can do so
with a specialization:

template <>
class is_printable<Foo>
{ public: static const bool value = false; };

Thanks!

At first I thought this works as I want it, but then I ran into this
snag. Google Test defines a function like this:

template <typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os << val;
}

I invoke it like this (for testing resolution):

int main(int argc, char* argv[])
{
MyClass foo( "bar" );
std::cout << "test " << foo << std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper( &std::cout, gtest );
std::cout << std::endl;
}

For some reason, my operator<<() gets chosen for the '<<' inside
GTestStreamToHelper, then it complains that std::string doesn't have a
print() method. Shouldn't it use a different operator<<() definition?

Thanks,
Gerhard
 
J

Juha Nieminen

Gerhard Fiedler said:
This

template <
class Printable,
typename std::enable_if <
std::is_member_function_pointer<
decltype(&Printable::print)

evaluates to the following for 'Printable' classes:

template < class Printable, int >

and to this for classes that aren't:

template < class Printable, 0 >

No. For classes that have no print() method std::enable_if::value is
undeclared (iow. there's no such name inside std::enable_if). This means
that the template above is invalid for any type that has no print() member
function.

Normally this would cause a compiler error because of the lacking 'value'
name. However, because of SFINAE the compiler will first check if there's
any other template that would match the specified type. If there is, then
it won't cause a compiler error. Only if there's no template whatsoever
that matches, then it will issue an error.

(SFINAE stands for "substitution failure is not an error", and means
exactly what I described above.)
 
V

Victor Bazarov

I'm still working on getting my original approach to work (please see
my other post in this thread if you're interested). I'm not yet
understanding well enough how I can limit the matching.

See http://stackoverflow.com/questions/...c-template-to-check-for-a-functions-existence
for a very good discussion of how to detect a member function.
Applying the principles discussed there to your program:

#include<iostream>
#include<type_traits>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template< class Printable>
typename std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout<< MyClass( "bar" )<< std::endl;
}

If you have types in your codebase that you want to exclude - say they
have a print member that serves some other purpose - you can do so
with a specialization:

template<>
class is_printable<Foo>
{ public: static const bool value = false; };

Thanks!

At first I thought this works as I want it, but then I ran into this
snag. Google Test defines a function like this:

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

I invoke it like this (for testing resolution):

int main(int argc, char* argv[])
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}

For some reason, my operator<<() gets chosen for the '<<' inside
GTestStreamToHelper, then it complains that std::string doesn't have a
print() method. Shouldn't it use a different operator<<() definition?

It will use the template that matches better. Unless the compiler has a
bug in it, that is. Please post the shortest code to replicate the
situation. Do so every time you need help with code not compiling or
not running the way you expect (again, see FAQ 5.8).

V
 
G

Gerhard Fiedler

Victor said:
On Thursday, June 21, 2012 7:59:23 AM UTC-5, Gerhard Fiedler wrote:
I'm still working on getting my original approach to work (please see
my other post in this thread if you're interested). I'm not yet
understanding well enough how I can limit the matching.

See http://stackoverflow.com/questions/...c-template-to-check-for-a-functions-existence
for a very good discussion of how to detect a member function.
Applying the principles discussed there to your program:

#include<iostream>
#include<type_traits>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template< class Printable>
typename std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout<< MyClass( "bar" )<< std::endl;
}

If you have types in your codebase that you want to exclude - say they
have a print member that serves some other purpose - you can do so
with a specialization:

template<>
class is_printable<Foo>
{ public: static const bool value = false; };

Thanks!

At first I thought this works as I want it, but then I ran into this
snag. Google Test defines a function like this:

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

I invoke it like this (for testing resolution):

int main(int argc, char* argv[])
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}

For some reason, my operator<<() gets chosen for the '<<' inside
GTestStreamToHelper, then it complains that std::string doesn't have a
print() method. Shouldn't it use a different operator<<() definition?

It will use the template that matches better. Unless the compiler has a
bug in it, that is. Please post the shortest code to replicate the
situation. Do so every time you need help with code not compiling or
not running the way you expect (again, see FAQ 5.8).

I thought that's what I did, but maybe not clear enough... The code in
question is cartec69's code, with the GTestStreamToHelper function as
posted, replacing cartec69's main() with the main() I posted:

#include <iostream>
#include <type_traits>

template <typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template <typename C> static yes& test( decltype(&C::print) );
template <typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template < class Printable >
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream &stream ) const { stream << str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout << MyClass( "bar" ) << std::endl;
}

template <typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os << val;
}

int main(int argc, char* argv[])
{
MyClass foo( "bar" );
std::cout << "test " << foo << std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper( &std::cout, gtest );
std::cout << std::endl;
}

Thanks,
Gerhard
 
V

Victor Bazarov

#include<iostream>
#include<type_traits>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template< class Printable>
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

int main(int argc, char* argv[])
{
std::cout<< MyClass( "bar" )<< std::endl;
}

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

int main(int argc, char* argv[])
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}

This:
---------------------------------------------->8 cut here
#include <iostream>
#include <type_traits>
#include <string>

template <typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template <typename C> static yes& test( decltype(&C::print) );
template <typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template<> class is_printable<std::string> {
public: static const bool value = false;
};

template < class Printable >
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream &stream ) const { stream << str; }
private:
char const *str;
};

template <typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os << val;
}

int main()
{
MyClass foo( "bar" );
std::cout << "test " << foo << std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper( &std::cout, gtest );
std::cout << std::endl;
}
---------------------------------------------->8 cut here
compiled for me fine with Visual C++ 2010. And the output was
test bar
gtest

Does that solve your problem?

V
 
G

Gerhard Fiedler

Victor said:
This:
---------------------------------------------->8 cut here
#include <iostream>
#include <type_traits>
#include <string>

template <typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template <typename C> static yes& test( decltype(&C::print) );
template <typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template<> class is_printable<std::string> {
public: static const bool value = false;
};

template < class Printable >
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream &stream ) const { stream << str; }
private:
char const *str;
};

template <typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os << val;
}

int main()
{
MyClass foo( "bar" );
std::cout << "test " << foo << std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper( &std::cout, gtest );
std::cout << std::endl;
}
---------------------------------------------->8 cut here
compiled for me fine with Visual C++ 2010. And the output was
test bar
gtest

Does that solve your problem?

I see... thanks for following up on this.

I can't (yet) tell whether this solves my problem -- because don't (yet)
understand how this works, and what I may have to do to make it work
generally.

When GTestStreamToHelper is used with T=std::string, it looks for an
operator<<( std::eek:stream &stream, std::string const & ), right? Why
doesn't it pick the right one, without explicit help? Shouldn't the
generic definition of is_printable tell it that std::string doesn't have
a print() member function?

The whole idea behind is_printable is that it is /automatically/ false
for classes that don't provide a print() member function. I don't
understand why it is necessary to explicitly tell the compiler that
std::string doesn't have one if it already knows this... Can somebody
please explain why this is necessary?

If I have to provide such an explicit "false" declaration for every
class that may be used as T with GTestStreamToHelper (and with any other
template function that may use an ostream operator<<), for me this
doesn't work.

Thanks again,
Gerhard
 
V

Victor Bazarov

Victor said:
This:
---------------------------------------------->8 cut here
#include<iostream>
#include<type_traits>
#include<string>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template<> class is_printable<std::string> {
public: static const bool value = false;
};

template< class Printable>
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

int main()
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}
---------------------------------------------->8 cut here
compiled for me fine with Visual C++ 2010. And the output was
test bar
gtest

Does that solve your problem?

I see... thanks for following up on this.

I can't (yet) tell whether this solves my problem -- because don't (yet)
understand how this works, and what I may have to do to make it work
generally.

When GTestStreamToHelper is used with T=std::string, it looks for an
operator<<( std::eek:stream&stream, std::string const& ), right? Why
doesn't it pick the right one, without explicit help? Shouldn't the
generic definition of is_printable tell it that std::string doesn't have
a print() member function?

The whole idea behind is_printable is that it is /automatically/ false
for classes that don't provide a print() member function. I don't
understand why it is necessary to explicitly tell the compiler that
std::string doesn't have one if it already knows this... Can somebody
please explain why this is necessary?

If I have to provide such an explicit "false" declaration for every
class that may be used as T with GTestStreamToHelper (and with any other
template function that may use an ostream operator<<), for me this
doesn't work.

My guess is that 'is_printable' is at fault. Comment out the operator<<
, the Google stuff, and replace your main with this:


int main()
{
std::cout << "MyClass : "
<< (is_printable<MyClass>::value ?
"printable" : "not printable") << std::endl;
std::cout << "std::string : "
<< (is_printable<std::string>::value ?
"printable" : "not printable") << std::endl;
}

and what do you get? I get that both are 'printable'. Need to debug
the 'is_printable' template. Looking into it...

V
 
V

Victor Bazarov

Victor said:
This:
---------------------------------------------->8 cut here
#include<iostream>
#include<type_traits>
#include<string>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template<> class is_printable<std::string> {
public: static const bool value = false;
};

template< class Printable>
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

int main()
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}
---------------------------------------------->8 cut here
compiled for me fine with Visual C++ 2010. And the output was
test bar
gtest

Does that solve your problem?

I see... thanks for following up on this.

I can't (yet) tell whether this solves my problem -- because don't (yet)
understand how this works, and what I may have to do to make it work
generally.

When GTestStreamToHelper is used with T=std::string, it looks for an
operator<<( std::eek:stream&stream, std::string const& ), right? Why
doesn't it pick the right one, without explicit help? Shouldn't the
generic definition of is_printable tell it that std::string doesn't have
a print() member function?

The whole idea behind is_printable is that it is /automatically/ false
for classes that don't provide a print() member function. I don't
understand why it is necessary to explicitly tell the compiler that
std::string doesn't have one if it already knows this... Can somebody
please explain why this is necessary?

If I have to provide such an explicit "false" declaration for every
class that may be used as T with GTestStreamToHelper (and with any other
template function that may use an ostream operator<<), for me this
doesn't work.

My guess is that 'is_printable' is at fault. Comment out the operator<<
, the Google stuff, and replace your main with this:


int main()
{
std::cout << "MyClass : "
<< (is_printable<MyClass>::value ?
"printable" : "not printable") << std::endl;
std::cout << "std::string : "
<< (is_printable<std::string>::value ?
"printable" : "not printable") << std::endl;
}

and what do you get? I get that both are 'printable'. Need to debug the
'is_printable' template. Looking into it...

Check out http://www.gockelhut.com/c++/articles/has_member .

I got to the point where in my solution (I won't give it here) the
'is_printable' works fine for all types that are classes, but fails for
built-in types. Then I found that page, but lack the time and
motivation to study it at the proper depth...

Good luck!

V
 
G

Gerhard Fiedler

Victor said:
Victor Bazarov wrote:

This:
---------------------------------------------->8 cut here
#include<iostream>
#include<type_traits>
#include<string>

template<typename T>
class is_printable
{
typedef char yes[1];
typedef char no[2];

template<typename C> static yes& test( decltype(&C::print) );
template<typename C> static no& test(...);

public:
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};

template<> class is_printable<std::string> {
public: static const bool value = false;
};

template< class Printable>
typename
std::enable_if<is_printable<Printable>::value,std::eek:stream&>::type
operator<<( std::eek:stream&stream, Printable const&printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::eek:stream&stream ) const { stream<< str; }
private:
char const *str;
};

template<typename T>
void GTestStreamToHelper(std::eek:stream* os, const T& val) {
*os<< val;
}

int main()
{
MyClass foo( "bar" );
std::cout<< "test "<< foo<< std::endl;

std::string const gtest( "gtest" );
GTestStreamToHelper(&std::cout, gtest );
std::cout<< std::endl;
}
---------------------------------------------->8 cut here
compiled for me fine with Visual C++ 2010. And the output was
test bar
gtest

Does that solve your problem?

I see... thanks for following up on this.

I can't (yet) tell whether this solves my problem -- because don't (yet)
understand how this works, and what I may have to do to make it work
generally.

When GTestStreamToHelper is used with T=std::string, it looks for an
operator<<( std::eek:stream&stream, std::string const& ), right? Why
doesn't it pick the right one, without explicit help? Shouldn't the
generic definition of is_printable tell it that std::string doesn't have
a print() member function?

The whole idea behind is_printable is that it is /automatically/ false
for classes that don't provide a print() member function. I don't
understand why it is necessary to explicitly tell the compiler that
std::string doesn't have one if it already knows this... Can somebody
please explain why this is necessary?

If I have to provide such an explicit "false" declaration for every
class that may be used as T with GTestStreamToHelper (and with any other
template function that may use an ostream operator<<), for me this
doesn't work.

My guess is that 'is_printable' is at fault. Comment out the operator<<
, the Google stuff, and replace your main with this:


int main()
{
std::cout << "MyClass : "
<< (is_printable<MyClass>::value ?
"printable" : "not printable") << std::endl;
std::cout << "std::string : "
<< (is_printable<std::string>::value ?
"printable" : "not printable") << std::endl;
}

and what do you get? I get that both are 'printable'. Need to debug the
'is_printable' template. Looking into it...

Check out http://www.gockelhut.com/c++/articles/has_member .

I got to the point where in my solution (I won't give it here) the
'is_printable' works fine for all types that are classes, but fails for
built-in types. Then I found that page, but lack the time and
motivation to study it at the proper depth...

Thanks a lot! Both for the (in hindsight obvious :) trick to check the
is_printable template alone, and for the link where an implementation is
described that does exactly what I'm after. I do have the motivation to
study it (and will make time), and I will post whatever I come up with.

Gerhard
 
8

88888 Dihedral

Gerhard Fiedleræ–¼ 2012å¹´6月20日星期三UTC+8上åˆ3時42分52秒寫é“:
Thank you for your response. In fact I didn't consider it at first,
reconsidered it after reading your post, and threw it out again :)

This is meant to work for an indeterminate number of classes of a bigger
system, some of which are not polymorphic at all for various reasons. I
don't want to put this constraint on all the classes that potentially
may want to use this interface.

If there was a way without polymorphism, I would prefer this.

Gerhard



Gerhard Fiedleræ–¼ 2012å¹´6月20日星期三UTC+8上åˆ3時42分52秒寫é“:
Thank you for your response. In fact I didn't consider it at first,
reconsidered it after reading your post, and threw it out again :)

This is meant to work for an indeterminate number of classes of a bigger
system, some of which are not polymorphic at all for various reasons. I
don't want to put this constraint on all the classes that potentially
may want to use this interface.

If there was a way without polymorphism, I would prefer this.

Gerhard

Lets face polymorphism seriously for a compiled program in the runtime.


V-tables of functors are necessary for objeccts with actions
in derived classes to use methods in their base classes propperly.
 
S

Sourav Datta

I still believe the solution with polymorphism is clearer and closer to what the initial requirement for a generic operator<< function was.

struct printable
{
virtual std::eek:stream& print(std::eek:stream&) const = 0;
};

std::eek:stream& operator<<(std::eek:stream& out, const printable& p)
{
return p.print(out);
}

Having the above definitions, any class can now inherit printable and implement the print method. Advantages:

1. No template tricks needed.
2. Imposes a definition on the class by making it "IS-A" printable - which is sort of consistent with what it does.
3. Imposes a restriction on how the print method should be implemented in a class - makes code consistent.

Example:

class Foo : public printable
{
public:
std::eek:stream& print(std::eek:stream& out) const
{
return out << "Hello foo";
}
};

class Bar : public printable
{
public:
std::eek:stream& print(std::eek:stream& out) const
{
return out << "Hello bar";
}
};

And use like:
std::cout << f << std::endl << Bar() << std::endl;

SD
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top