Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Generic ostream operator<<?

179 views
Skip to first unread message

Gerhard Fiedler

unread,
Jun 19, 2012, 3:30:00 PM6/19/12
to
Hello,

I want to be able to stream custom classes to ostreams like this:

MyClass foo;
myStream << foo;

AIUI, this requires an operator<<() with this signature:

std::ostream &operator<<( std::ostream &str, MyClass const &printable );

In order to avoid creating such a function for every class, I tried a
template like this:

template < class Printable >
std::ostream &operator<<( std::ostream &stream,
Printable const &printable )
{
printable.print( stream );
return stream;
}

(All the classes in question have a public member function "void print(
std::ostream &stream )".)


However, with this I get tons of errors like "'operator <<' is
ambiguous".

Is there a way to define this template function so that it is only
instantiated for classes that implement this print() function? (I could
make the name such that it is very unlikely that any other class has
such a name.)

Or is there another way to avoid having to define such a global
operator<< for every class with ostream support?

Thanks,
Gerhard

Victor Bazarov

unread,
Jun 19, 2012, 3:36:39 PM6/19/12
to
On 6/19/2012 3:30 PM, Gerhard Fiedler wrote:
> I want to be able to stream custom classes to ostreams like this:
>
> MyClass foo;
> myStream<< foo;
>
> AIUI, this requires an operator<<() with this signature:
>
> std::ostream&operator<<( std::ostream&str, MyClass const&printable );
>
> In order to avoid creating such a function for every class, I tried a
> template like this:
>
> template< class Printable>
> std::ostream&operator<<( std::ostream&stream,
> Printable const&printable )
> {
> printable.print( stream );
> return stream;
> }
>
> (All the classes in question have a public member function "void print(
> std::ostream&stream )".)
>
>
> However, with this I get tons of errors like "'operator<<' is
> ambiguous".
>
> Is there a way to define this template function so that it is only
> instantiated for classes that implement this print() function? (I could
> make the name such that it is very unlikely that any other class has
> such a name.)
>
> Or is there another way to avoid having to define such a global
> operator<< for every class with ostream support?

Have you considered using polymorphism at all, or is it out of fashion
already?

struct Printable
{
virtual void print(std::ostream& os) const = 0;
};

class GerhardsClass : public Printable
{
...
void print(std::ostream& os) const; // whatever you have
};

// no need for the template
ostream& operator <<(ostream& os, Printable const& pr)
{
pr.print(os);
return os;
}

V
--
I do not respond to top-posted replies, please don't ask

Gerhard Fiedler

unread,
Jun 19, 2012, 3:42:52 PM6/19/12
to
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

Victor Bazarov

unread,
Jun 19, 2012, 3:57:32 PM6/19/12
to
OK, that's fair. If you don't want to introduce polymorphism, then you
will have to give the exact example where your solution does not work,
which we then should be able to fix. Otherwise, it's going to be an
exercise in futility on our part: we give you a solution, and you tell
us it's not working due to "tons of errors". See FAQ 5.8.

Rui Maciel

unread,
Jun 19, 2012, 4:01:52 PM6/19/12
to
Gerhard Fiedler wrote:

> Hello,
>
> I want to be able to stream custom classes to ostreams like this:
>
> MyClass foo;
> myStream << foo;
>
> AIUI, this requires an operator<<() with this signature:
>
> std::ostream &operator<<( std::ostream &str, MyClass const &printable );
>
> In order to avoid creating such a function for every class, I tried a
> template like this:
>
> template < class Printable >
> std::ostream &operator<<( std::ostream &stream,
> Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> (All the classes in question have a public member function "void print(
> std::ostream &stream )".)

Aren't you trying to avoid the need to define a operator<<() for each class
with the requirement of not only defining a print() for each class but also
wrap it in some template function?


Rui Maciel

Gerhard Fiedler

unread,
Jun 19, 2012, 4:51:54 PM6/19/12
to
Sort of, yes :)

These are the two basic approaches I see:

1) Define something like my .print() member function that does the
actual streaming (that is, accessing private/protected members etc.) and
additionally an operator<<() that is not a member of the class that then
calls the .print() member function. (My question is about a variant of
this approach, where the individual operator<<() functions are replaced
by a single template.)

2) Define a free function operator<<() for each class that essentially
does what my .print() function does. For this, it needs to be a friend
of the class.

Is there another approach?

It seems to me that you're implying that approach 2 is simpler. I can
see how it can be, sort of, from a given angle, but I don't like the
friend declaration. This causes this implementation to affect one
location more than approach 1 (no friend) and a single template
operator<<(). Mostly a matter of taste, probably.

Gerhard

Gerhard Fiedler

unread,
Jun 19, 2012, 5:20:22 PM6/19/12
to
Got it. I thought this was a rather common issue with a rather generic
answer...

It seems that because there is already a templated operator for some
types, there is now a second, ambiguous definition. Hence my question
whether I can use some template tricks to restrict my template to
classes that implement a given function; I don't want my template
function to be considered for the type 'const char *'.

Thanks,
Gerhard


#include <iostream>

template < class Printable >
std::ostream &operator<<( std::ostream &stream,
Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
// The next line is line 122:
void print( std::ostream &stream ) const { stream << str; }
private:
char const *str;
};

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


Error (with VC++ 10):

1>TestApp.cpp(122): error C2593: 'operator <<' is ambiguous
1> TestApp.cpp(112): could be 'std::ostream &operator <<<const
char*>(std::ostream &,const Printable &)'
1> with
1> [
1> Printable=const char *
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio
10.0\VC\include\ostream(851): or
'std::basic_ostream<_Elem,_Traits> &std::operator
<<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits>
&,const _Elem *)' [found using argument-dependent lookup]
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio
10.0\VC\include\ostream(764): or
'std::basic_ostream<_Elem,_Traits> &std::operator
<<<std::char_traits<char>>(std::basic_ostream<_Elem,_Traits> &,const
char *)' [found using argument-dependent lookup]
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio
10.0\VC\include\ostream(679): or
'std::basic_ostream<_Elem,_Traits> &std::operator
<<<char,std::char_traits<char>>(std::basic_ostream<_Elem,_Traits>
&,const char *)' [found using argument-dependent lookup]
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> while trying to match the argument list '(std::ostream,
const char *const )'

Luca Risolia

unread,
Jun 19, 2012, 6:44:03 PM6/19/12
to
On 19/06/2012 21:30, Gerhard Fiedler wrote:
> Is there a way to define this template function so that it is only
> instantiated for classes that implement this print() function? (I could
> make the name such that it is very unlikely that any other class has
> such a name.)

Yes, there is a way:

#include <type_traits>

template < class Printable,
typename std::enable_if<std::is_member_function_pointer
<decltype(&Printable::print)>::value, int>::type= 0 >

Rui Maciel

unread,
Jun 19, 2012, 7:11:14 PM6/19/12
to
Gerhard Fiedler wrote:z

> Sort of, yes :)
>
> These are the two basic approaches I see:
>
> 1) Define something like my .print() member function that does the
> actual streaming (that is, accessing private/protected members etc.) and
> additionally an operator<<() that is not a member of the class that then
> calls the .print() member function. (My question is about a variant of
> this approach, where the individual operator<<() functions are replaced
> by a single template.)
>
> 2) Define a free function operator<<() for each class that essentially
> does what my .print() function does. For this, it needs to be a friend
> of the class.
>
> Is there another approach?
>
> It seems to me that you're implying that approach 2 is simpler. I can
> see how it can be, sort of, from a given angle, but I don't like the
> friend declaration.

You only need to declare operator<<() as friend if your ouput routine
requires access to non-public members. If all the data is available through
public members then this requirement ceases to exist.

Considering that you are willing to output that information without any
restriction (i.e., output to std::cout) then it is a good indicator that you
don't really want to hide it from everyone. Also, it is better to force
components to access data through interfaces instead of granting access to
raw data, as it gives you some leeway to refactor the entrails of your class
without having to deal with a cascade of problems spreading through your
project. Hence, as you are already willing to add members to your classes,
nothing stops you from adding the relevant get() members that let you define
an unfriendly operator<<().

Nonetheless, this means that you would still be adding at least a member
function to each of your classes, and then defining a operator<<() based on
them. That is, this solution would require you to add at least two member
functions to each of your classes. With this in mind, it would be far
simpler and straight-forward to just add the only method that is actually
needed, a friendly operator<<(), and move on to other ventures.


Rui Maciel

Gerhard Fiedler

unread,
Jun 19, 2012, 9:13:43 PM6/19/12
to
Rui Maciel wrote:

> Gerhard Fiedler wrote:z
>
>> Sort of, yes :)
>>
>> These are the two basic approaches I see:
>>
>> 1) Define something like my .print() member function that does the
>> actual streaming (that is, accessing private/protected members etc.) and
>> additionally an operator<<() that is not a member of the class that then
>> calls the .print() member function. (My question is about a variant of
>> this approach, where the individual operator<<() functions are replaced
>> by a single template.)
>>
>> 2) Define a free function operator<<() for each class that essentially
>> does what my .print() function does. For this, it needs to be a friend
>> of the class.
>>
>> Is there another approach?
>>
>> It seems to me that you're implying that approach 2 is simpler. I can
>> see how it can be, sort of, from a given angle, but I don't like the
>> friend declaration.
>
> You only need to declare operator<<() as friend if your ouput routine
> requires access to non-public members. If all the data is available
> through public members then this requirement ceases to exist.

Agreed.

> Considering that you are willing to output that information without
> any restriction (i.e., output to std::cout) [...]

I don't know where you get this from. If you mean the code that I posted
in response to Victor, you're way in fantasy land. Victor asked me for
an example that demonstrates the errors I'm seeing, and that's what I
sent. Any other conclusions are mere imagination. I thought that this
was common practice here... providing example code that shows what one
wants to show -- only, at least as far as possible. (To show the whole
context, I'd have to bury you guys with hundreds of lines of code and
several pages of system design documentation, but nothing of this has to
do with my question.)

The remainder of your post is pretty far off from my situation as
described in my previous posts, so any discussion of it from my part
seems a waste of effort.

Thanks anyway, though.

Gerhard

Gerhard Fiedler

unread,
Jun 19, 2012, 9:16:13 PM6/19/12
to
Aha! I had the distinct impression that there was something along these
lines, but this way of using templates is still not fluent for me. I
guess this either works or it gets me going towards something that will
work for my purposes.

Thank you... the only post so far that actually answered my question! :)

Gerhard

Gerhard Fiedler

unread,
Jun 20, 2012, 8:51:36 AM6/20/12
to
Ok... Now I had some time experimenting with this approach.

Your proposal, as-is (used with the code I posted here before), gives me
"error C4519: default template arguments are only allowed on a class
template" (VC++ 10). Is this a limitation of VC++ or a problem with the
code?


I also tried a similar but different version, using the return type:

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

This gave me "error C2039: 'type' : is not a member of
'std::tr1::enable_if<_Test,_Type>'
1> with
1> [
1> _Test=false,
1> _Type=std::ostream &
1> ]"


Can somebody please help me to massage the template definition to do
what I want?

Thanks,
Gerhard

Victor Bazarov

unread,
Jun 20, 2012, 10:38:40 AM6/20/12
to
> class MyClass
> {
> public:
> MyClass( char const *val ) : str( val ) {}
> // The next line is line 122:
> void print( std::ostream&stream ) const { stream<< str; }
> private:
> char const *str;
> };
>
> int main(int argc, char* argv[])
> {
> MyClass foo( "bar" );
> cout<< foo<< endl;

Nit pick:
std::cout << foo<< std::endl;
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):

#include <iostream>

template<class T> struct Printable
{
friend std::ostream& operator <<(std::ostream& os,
Printable const& rp)
{
return static_cast<T const&>(rp).print(os);
}
};

class MyClass : public Printable<MyClass>
{
public:
explicit MyClass( char const *val ) : str( val ) {}
// The next line is line 122:
std::ostream& print( std::ostream &stream ) const {
return stream << str; }
private:
char const *str;
};


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

Rui Maciel

unread,
Jun 20, 2012, 10:55:59 AM6/20/12
to
Gerhard Fiedler wrote:

>> Considering that you are willing to output that information without
>> any restriction (i.e., output to std::cout) [...]
>
> I don't know where you get this from. If you mean the code that I posted
> in response to Victor,
<snip/>

It appears you failed to understand what I said, in addition to being
needlessly rude. I was referring to encapsulation, and how you are trying
to needlessly jump through hoops to try to defeat the restrictions that you
chose to put up, particularly when there are solutions which are obvious and
straight-forward.

As you manifested an irrational desire to avoid the straight-forward
solution, defining operator<<() as friend, and you also exhibited a fixation
to employ redundant and useless wrapper functions for what essentially is
the definition of a operator<<(), I pointed out the obvious alternative:
define the necessary getter functions, define your non-friend operator<<()
so that it uses that interface and you won't have to employ friendship
declarations.

But hey, if that's your thing then, as Ernie Anastos said; "keep fucking
that chicken".


Rui Maciel

Gerhard Fiedler

unread,
Jun 20, 2012, 12:03:27 PM6/20/12
to
Rui Maciel wrote:

> Gerhard Fiedler wrote:
>
>>> Considering that you are willing to output that information without
>>> any restriction (i.e., output to std::cout) [...]
>>
>> I don't know where you get this from. If you mean the code that I posted
>> in response to Victor,
> <snip/>
>
> It appears you failed to understand what I said,

Given what you again wrote here, it appears that I did understand what
you meant. It however appears that you fail to consider what I wrote
about my situation.

> I was referring to encapsulation, and how you are trying to needlessly
> jump through hoops to try to defeat the restrictions that you chose
> to put up, particularly when there are solutions which are obvious
> and straight-forward.

I have my reasons for those restrictions, and I'm not trying to defeat
them. You may or may not agree with my reasons, but you don't know them
and so far you haven't been interested in them. You are trying to look
at the greater picture, which is a good thing, usually, but not without
knowing the context.

In this case, I'm simply interested in the question whether I can
restrict the template definition of a function to classes that implement
a given member -- as stated in the OP.

> As you manifested an irrational desire to avoid the straight-forward
> solution, defining operator<<() as friend,

Not sure what you call irrational. Given that you don't know my reasons
(and have so far shown no desire to know them), how can you judge
whether this exercise is rational or not?

> and you also exhibited a fixation to employ redundant and useless
> wrapper functions for what essentially is the definition of a
> operator<<(),

It seems you forgot my original question. I don't want to employ wrapper
function/s/, but one single wrapper function. This is one purpose of
this exercise.

> I pointed out the obvious alternative: define the necessary getter
> functions, define your non-friend operator<<() so that it uses that
> interface and you won't have to employ friendship declarations.

This is the "standard" solution, and it is used often enough. I know it.
In this particular case, this is possible but not that desirable. This
is why I'm trying to see whether I can solve this in the way I asked
about.

If you find this exercise irrational, what is then your participation in
it? (Not that it's not appreciated, but I have my reasons to do it, and
for me this is not only rational but also fruitful so far. For you?)

Gerhard

Rui Maciel

unread,
Jun 20, 2012, 2:16:42 PM6/20/12
to
Gerhard Fiedler wrote:

> Rui Maciel wrote:
>
>> Gerhard Fiedler wrote:
>>
>>>> Considering that you are willing to output that information without
>>>> any restriction (i.e., output to std::cout) [...]
>>>
>>> I don't know where you get this from. If you mean the code that I posted
>>> in response to Victor,
>> <snip/>
>>
>> It appears you failed to understand what I said,
>
> Given what you again wrote here, it appears that I did understand what
> you meant. It however appears that you fail to consider what I wrote
> about my situation.

You already demonstrated that you were clueless about what I wrote, to the
point that I really doubt you even took the time to actually read it.


>> I was referring to encapsulation, and how you are trying to needlessly
>> jump through hoops to try to defeat the restrictions that you chose
>> to put up, particularly when there are solutions which are obvious
>> and straight-forward.
>
> I have my reasons for those restrictions, and I'm not trying to defeat
> them. You may or may not agree with my reasons, but you don't know them
> and so far you haven't been interested in them. You are trying to look
> at the greater picture, which is a good thing, usually, but not without
> knowing the context.


You presented a set of details which you personally picked after deciding
they were the only relevant aspects which influenced your problem. If you
believe the details you've presented are insufficient to properly analyze
your problem and that you didn't provided the adequate context then I don't
see how your decision to leave out information you deemed relevant should be
used as a basis to condemn and insult others.

In spite of this, if you read the post you wrote then you will notice that
you explicitly stated the following:
1) you wished to define a set of operator<<() to output the content of some
classes to std::ostream
2) you required a definition similar to
std::ostream &operator<<( std::ostream &str, MyClass const &printable );
3) you've came up with a implementation of a template policy pattern by
adding individual print() methods to each class, which you failed to make it
work, and asked for help
4) then, in addition, you asked if there was "another way to avoid having to
define such a global operator<< for every class with ostream support"

In my reply, I explicitly addressed 1), 2) and 4), leaving out 3) as it
represented a needlessly convoluted and, ultimately, unjustifiably laborious
solution to a simple problem with a straight-forward solution.


> In this case, I'm simply interested in the question whether I can
> restrict the template definition of a function to classes that implement
> a given member -- as stated in the OP.

Yes, you can. You just need to implement a template strategy pattern to
wrap your print() methods and add compiler checks to check for their
existence. With C++11, you can implement them like Luca Risolia already
explained, but with previous versions you either implement the relevant type
traits or you need to rely on third-party libraries, such as Boost's
Boost.type_traits.


>> As you manifested an irrational desire to avoid the straight-forward
>> solution, defining operator<<() as friend,
>
> Not sure what you call irrational. Given that you don't know my reasons
> (and have so far shown no desire to know them), how can you judge
> whether this exercise is rational or not?

The people in this newsgroup are only aware of the reasons you presented.
Again, if you believe that you haven't provided enough details for others to
adequately understand your reasons then you should try to do a better job
presenting them, particularly when you believe that others aren't seeing the
full picture due to your inability to show it.


>> and you also exhibited a fixation to employ redundant and useless
>> wrapper functions for what essentially is the definition of a
>> operator<<(),
>
> It seems you forgot my original question. I don't want to employ wrapper
> function/s/, but one single wrapper function. This is one purpose of
> this exercise.

Your template policy pattern is nothing more than a thin wrapper over your
classes' print() method. You yourself defined it as nothing more than:

template < class Printable >
std::ostream &operator<<( std::ostream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

I don't believe it is possible to write a thinner wrapper than this.


>> I pointed out the obvious alternative: define the necessary getter
>> functions, define your non-friend operator<<() so that it uses that
>> interface and you won't have to employ friendship declarations.
>
> This is the "standard" solution, and it is used often enough. I know it.
> In this particular case, this is possible but not that desirable.

As you provided no justification or reasoning for this fixation and yet it
appears you don't to steer away from it, do you understand why your decision
has been described as irrational?


> This
> is why I'm trying to see whether I can solve this in the way I asked
> about.

It looks like a case of "give me what I want, not what I asked for".


> If you find this exercise irrational, what is then your participation in
> it? (Not that it's not appreciated, but I have my reasons to do it, and
> for me this is not only rational but also fruitful so far. For you?)

You asked for help and I tried to help you. That's one of the main reasons
people still subscribe to this newsgroup. But, after you posted your
replies, I've realized that that was a mistake.


Rui Maciel

Bo Persson

unread,
Jun 20, 2012, 4:22:36 PM6/20/12
to
The error message is correct for C++03. Default template arguments for
functions has been added to C++11, and is supported by some compilers.

VC10 is not aware of that.

>
> I also tried a similar but different version, using the return type:
>
> template < class Printable >
> typename std::enable_if <
> std::is_member_function_pointer <
> decltype( &Printable::print ) >::value
> , std::ostream &
>> ::type
> operator<<( std::ostream &stream, Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> This gave me "error C2039: 'type' : is not a member of
> 'std::tr1::enable_if<_Test,_Type>'
> 1> with
> 1> [
> 1> _Test=false,
> 1> _Type=std::ostream &
> 1> ]"
>
>
> Can somebody please help me to massage the template definition to do
> what I want?
>

I believe this is similar to the above. C++11 has added more cases where
SFINAE can be used. VC10 complains that the function in invalid for
types without a print member.


Bo Persson



Gerhard Fiedler

unread,
Jun 20, 2012, 6:35:29 PM6/20/12
to
Thanks for the confirmation.

Gerhard

Gerhard Fiedler

unread,
Jun 21, 2012, 8:36:46 AM6/21/12
to
Rui Maciel wrote:

> Gerhard Fiedler wrote:
>
>> Rui Maciel wrote:
>>
>>> Gerhard Fiedler wrote:
>>>

> [...] should be used as a basis to condemn and insult others.

You stated repeatedly that I insulted you and/or others. I'm sorry if
you feel that way; it was not my intention. Since you fail to provide
specifics, I don't even know with what you feel I insulted you and/or
others.

>> In this case, I'm simply interested in the question whether I can
>> restrict the template definition of a function to classes that
>> implement a given member -- as stated in the OP.
>
> Yes, you can. You just need to implement a template strategy pattern
> to wrap your print() methods and add compiler checks to check for
> their existence. With C++11, you can implement them like Luca
> Risolia already explained, but with previous versions you either
> implement the relevant type traits or you need to rely on third-party
> libraries, such as Boost's Boost.type_traits.

Thanks. I'm looking at Boost's type_traits library. But so far I can't
figure out how to use it to answer my first question (see the OP or the
end of this post).

> The people in this newsgroup are only aware of the reasons you
> presented. Again, if you believe that you haven't provided enough
> details for others to adequately understand your reasons then you
> should try to do a better job presenting them, particularly when you
> believe that others aren't seeing the full picture due to your
> inability to show it.

I thought that for the purposes of my question, the picture was enough.
It was enough for Luca, wasn't it? The answers you're giving are for a
question that I didn't ask, that's why there's information missing.

>> It seems you forgot my original question. I don't want to employ
>> wrapper function/s/, but one single wrapper function. This is one
>> purpose of this exercise.
>
> Your template policy pattern is nothing more than a thin wrapper over your
> classes' print() method. You yourself defined it as nothing more than:
>
> template < class Printable >
> std::ostream &operator<<( std::ostream &stream, Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> I don't believe it is possible to write a thinner wrapper than this.

It's the language and its common usage patterns with streaming that
require this wrapper. I just want to make (a single) one that works,
with the compilers I'm interested in (gcc 4.6, VC++ 10). This one
doesn't work.

>>> I pointed out the obvious alternative: define the necessary getter
>>> functions, define your non-friend operator<<() so that it uses that
>>> interface and you won't have to employ friendship declarations.
>>
>> This is the "standard" solution, and it is used often enough. I know
>> it. In this particular case, this is possible but not that
>> desirable.
>
> As you provided no justification or reasoning for this fixation and
> yet it appears you don't to steer away from it, do you understand why
> your decision has been described as irrational?

You may or may not understand my reasons, you may or may not agree with
them, but neither of this indicates necessarily irrationality on my end.
This whole sub-thread with you seems largely irrational... (and it
always takes two for such a conversation :)

Anyway, this is for a trace/debug logging facility. It's used with
hundreds of classes, potentially, by dozens of developers, potentially.
It should be as simple as possible to stream relevant contents of a
class to an ostream. Adding a single public member to a class without
further modifying the class seems to be the minimum necessary, and if
it's not a whole lot of effort, to me it's worth getting there.

Now, the effort I'm employing here is more, for mainly two reasons.

One is that I thought this was a good opportunity to get myself educated
about enabling/disabling templates for certain conditions. I've seen
code like this every now and then, and I can mostly figure out what it
does, but I've never written conditional templates and there are some
gaps I have to fill.

The other is that I'm taking this conversation with you in areas that
are way off my original objective, mostly for respect for you and your
attempt to help me.

>> This is why I'm trying to see whether I can solve this in the way I
>> asked about.
>
> It looks like a case of "give me what I want, not what I asked for".

Not quite. Let me cite the two question from my OP:

"Is there a way to define this template function [the thin wrapper you
cited above] so that it is only instantiated for classes that implement
this print() function?"

Apparently this was clear enough for Luca to "get it". To me, it seems a
very clear question that doesn't need more context than what I gave.

And:

"Or is there another way to avoid having to define such a global
operator<< for every class with ostream support?"

Same here. None of your answers has even attempted to address either of
these two questions. (In your last post, you answered "yes" to the first
question -- after someone else already posted how to do it.) While I
appreciate the effort of getting at the bigger picture, I think my
questions were clear enough, and I provided enough information for
whoever was willing to answer them (that is, them and not some other
question) to do so.

Gerhard

Gerhard Fiedler

unread,
Jun 21, 2012, 8:54:24 AM6/21/12
to
Thanks again to Luca for posting this. Apparently, this is valid C++11,
but not supported by VC++ 10. I'm looking for a solution that works with
VC++ 10 and gcc 4.6.

At this point, I'm trying to better understand how this works. This is
what I currently think I understand:

This

template <
class Printable,
typename std::enable_if <
std::is_member_function_pointer<
decltype(&Printable::print)
>::value,
int
>::type = 0
>

evaluates to the following for 'Printable' classes:

template < class Printable, int >

and to this for classes that aren't:

template < class Printable, 0 >

What I don't understand is why this prevents this template from matching
non-Printable classes.


The second question I have is how to use the Boost type_traits to
implement this, without using a default template argument. Reading some
of the library documentation, it seems that it is mostly based on
template functions that evaluate to either true_type or false_type. In
the examples they use these two types to defer to different
implementations for different conditions, using simple signature
matching (true_type and false_type are two distinct types). An example
of this approach is
<http://www.boost.org/doc/libs/1_46_1/libs/type_traits/doc/html/boost_typetraits/examples/iter.html>.

However, I yet fail to see how this mechanism can be used to avoid that
a template matches a given case; it only seems to work for switching
between different implementations, not for avoiding a match. (Once the
template is matched, simply not providing an implementation for one of
the cases doesn't seem to work.) Part of my limitation here is also that
I don't yet understand what prevents the match in Luca's solution.

Can someone please show me how I can use the Boost type_traits to avoid
a match on the original template (similar to what Luca's code does), or
point me to an example or tutorial where this is show?

Thanks,
Gerhard

Gerhard Fiedler

unread,
Jun 21, 2012, 8:59:23 AM6/21/12
to
Victor Bazarov wrote:

> 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

cart...@gmail.com

unread,
Jun 21, 2012, 11:02:04 AM6/21/12
to
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/257288/is-it-possible-to-write-a-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::ostream&>::type
operator<<( std::ostream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::ostream &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; };

Gerhard Fiedler

unread,
Jun 21, 2012, 4:23:27 PM6/21/12
to
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::ostream* 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

Juha Nieminen

unread,
Jun 21, 2012, 5:15:13 PM6/21/12
to
Gerhard Fiedler <gel...@gmail.com> wrote:
> This
>
> template <
> class Printable,
> typename std::enable_if <
> std::is_member_function_pointer<
> decltype(&Printable::print)
> >::value,
> int
> >::type = 0
> >
>
> 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.)

Victor Bazarov

unread,
Jun 22, 2012, 9:14:56 AM6/22/12
to
On 6/21/2012 4:23 PM, Gerhard Fiedler wrote:
> cart...@gmail.com wrote:
>
>> 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/257288/is-it-possible-to-write-a-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::ostream&>::type
>> operator<<( std::ostream&stream, Printable const&printable )
>> {
>> printable.print( stream );
>> return stream;
>> }
>>
>> class MyClass
>> {
>> public:
>> MyClass( char const *val ) : str( val ) {}
>> void print( std::ostream&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::ostream* 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).

Gerhard Fiedler

unread,
Jun 24, 2012, 11:52:10 PM6/24/12
to
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::ostream&>::type
operator<<( std::ostream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std::ostream &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::ostream* 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

Victor Bazarov

unread,
Jun 25, 2012, 7:48:48 AM6/25/12
to
> template<typename T>
> void GTestStreamToHelper(std::ostream* 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::ostream&>::type
operator<<( std::ostream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

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

template <typename T>
void GTestStreamToHelper(std::ostream* 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?

Gerhard Fiedler

unread,
Jun 25, 2012, 10:07:45 AM6/25/12
to
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::ostream &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

Victor Bazarov

unread,
Jun 25, 2012, 10:45:52 AM6/25/12
to
On 6/25/2012 10:07 AM, Gerhard Fiedler wrote:
> 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::ostream&>::type
>> operator<<( std::ostream&stream, Printable const&printable )
>> {
>> printable.print( stream );
>> return stream;
>> }
>>
>> class MyClass
>> {
>> public:
>> MyClass( char const *val ) : str( val ) {}
>> void print( std::ostream&stream ) const { stream<< str; }
>> private:
>> char const *str;
>> };
>>
>> template<typename T>
>> void GTestStreamToHelper(std::ostream* 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::ostream&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...

Victor Bazarov

unread,
Jun 25, 2012, 12:31:13 PM6/25/12
to
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!

Gerhard Fiedler

unread,
Jun 26, 2012, 11:00:13 AM6/26/12
to
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

88888 Dihedral

unread,
Jun 26, 2012, 8:46:06 PM6/26/12
to
Gerhard Fiedler於 2012年6月20日星期三UTC+8上午3時42分52秒寫道:
> Victor Bazarov wrote:
>
> > On 6/19/2012 3:30 PM, Gerhard Fiedler wrote:
> >> I want to be able to stream custom classes to ostreams like this:
> >>
> >> MyClass foo;
> >> myStream<< foo;
> >>
> >> AIUI, this requires an operator<<() with this signature:
> >>
> >> std::ostream&operator<<( std::ostream&str, MyClass const&printable );
> >>
> >> In order to avoid creating such a function for every class, I tried a
> >> template like this:
> >>
> >> template< class Printable>
> >> std::ostream&operator<<( std::ostream&stream,
> >> Printable const&printable )
> >> {
> >> printable.print( stream );
> >> return stream;
> >> }
> >>
> >> (All the classes in question have a public member function "void print(
> >> std::ostream&stream )".)
> >>
> >>
> >> However, with this I get tons of errors like "'operator<<' is
> >> ambiguous".
> >>
> >> Is there a way to define this template function so that it is only
> >> instantiated for classes that implement this print() function? (I could
> >> make the name such that it is very unlikely that any other class has
> >> such a name.)
> >>
> >> Or is there another way to avoid having to define such a global
> >> operator<< for every class with ostream support?
> >
> > Have you considered using polymorphism at all, or is it out of fashion
> > already?
>
> 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秒寫道:
> Victor Bazarov wrote:
>
> > On 6/19/2012 3:30 PM, Gerhard Fiedler wrote:
> >> I want to be able to stream custom classes to ostreams like this:
> >>
> >> MyClass foo;
> >> myStream<< foo;
> >>
> >> AIUI, this requires an operator<<() with this signature:
> >>
> >> std::ostream&operator<<( std::ostream&str, MyClass const&printable );
> >>
> >> In order to avoid creating such a function for every class, I tried a
> >> template like this:
> >>
> >> template< class Printable>
> >> std::ostream&operator<<( std::ostream&stream,
> >> Printable const&printable )
> >> {
> >> printable.print( stream );
> >> return stream;
> >> }
> >>
> >> (All the classes in question have a public member function "void print(
> >> std::ostream&stream )".)
> >>
> >>
> >> However, with this I get tons of errors like "'operator<<' is
> >> ambiguous".
> >>
> >> Is there a way to define this template function so that it is only
> >> instantiated for classes that implement this print() function? (I could
> >> make the name such that it is very unlikely that any other class has
> >> such a name.)
> >>
> >> Or is there another way to avoid having to define such a global
> >> operator<< for every class with ostream support?
> >
> > Have you considered using polymorphism at all, or is it out of fashion
> > already?
>
> 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.


Sourav Datta

unread,
Jun 27, 2012, 5:33:41 AM6/27/12
to
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::ostream& print(std::ostream&) const = 0;
};

std::ostream& operator<<(std::ostream& 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::ostream& print(std::ostream& out) const
{
return out << "Hello foo";
}
};

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

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

SD

On Wednesday, June 20, 2012 1:00:00 AM UTC+5:30, Gerhard Fiedler wrote:
> Hello,
>
> I want to be able to stream custom classes to ostreams like this:
>
> MyClass foo;
> myStream << foo;
>
> AIUI, this requires an operator<<() with this signature:
>
> std::ostream &operator<<( std::ostream &str, MyClass const &printable );
>
> In order to avoid creating such a function for every class, I tried a
> template like this:
>
> template < class Printable >
> std::ostream &operator<<( std::ostream &stream,
> Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> (All the classes in question have a public member function "void print(
> std::ostream &stream )".)
>
>
> However, with this I get tons of errors like "'operator <<' is
> ambiguous".
>
> Is there a way to define this template function so that it is only
> instantiated for classes that implement this print() function? (I could
> make the name such that it is very unlikely that any other class has
> such a name.)
>
> Or is there another way to avoid having to define such a global
> operator<< for every class with ostream support?
>
> Thanks,
> Gerhard
0 new messages