Go Back   Rhinocerus > Newsgroup > Newsgroup comp.language.c++

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 06-19-2012, 07:30 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Generic ostream operator<<?

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:stream &operator<<( std:stream &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:stream &operator<<( std:stream &stream,
Printable const &printable )
{
printable.print( stream );
return stream;
}

(All the classes in question have a public member function "void print(
std:stream &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
Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 06-19-2012, 07:36 PM
Victor Bazarov
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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:stream&operator<<( std:stream&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:stream&operator<<( std:stream&stream,
> Printable const&printable )
> {
> printable.print( stream );
> return stream;
> }
>
> (All the classes in question have a public member function "void print(
> std:stream&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:stream& os) const = 0;
};

class GerhardsClass : public Printable
{
...
void print(std:stream& 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
Reply With Quote
  #3 (permalink)  
Old 06-19-2012, 08:01 PM
Rui Maciel
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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:stream &operator<<( std:stream &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:stream &operator<<( std:stream &stream,
> Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> (All the classes in question have a public member function "void print(
> std:stream &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
Reply With Quote
  #4 (permalink)  
Old 06-19-2012, 08:51 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Rui Maciel wrote:

> 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:stream &operator<<( std:stream &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:stream &operator<<( std:stream &stream,
>> Printable const &printable )
>> {
>> printable.print( stream );
>> return stream;
>> }
>>
>> (All the classes in question have a public member function "void print(
>> std:stream &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?


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
Reply With Quote
  #5 (permalink)  
Old 06-19-2012, 10:44 PM
Luca Risolia
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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:rint)>::value, int>::type= 0 >
std:stream &operator<<( std:stream &stream,
Printable const &printable )
{
printable.print( stream );
return stream;
}
Reply With Quote
  #6 (permalink)  
Old 06-19-2012, 11:11 PM
Rui Maciel
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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
Reply With Quote
  #7 (permalink)  
Old 06-20-2012, 01:16 AM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Luca Risolia wrote:

> 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:rint)>::value, int>::type= 0 >
> std:stream &operator<<( std:stream &stream,
> Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }


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
Reply With Quote
  #8 (permalink)  
Old 06-20-2012, 12:51 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Gerhard Fiedler wrote:

> Luca Risolia wrote:
>
>> 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:rint)>::value, int>::type= 0 >
>> std:stream &operator<<( std:stream &stream,
>> Printable const &printable )
>> {
>> printable.print( stream );
>> return stream;
>> }

>
> 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!


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:rint ) >::value
, std:stream &
>::type

operator<<( std:stream &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:stream &
1> ]"


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

Thanks,
Gerhard
Reply With Quote
  #9 (permalink)  
Old 06-20-2012, 08:22 PM
Bo Persson
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Gerhard Fiedler skrev 2012-06-20 14:51:
> Gerhard Fiedler wrote:
>
>> Luca Risolia wrote:
>>
>>> 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:rint)>::value, int>::type= 0 >
>>> std:stream &operator<<( std:stream &stream,
>>> Printable const &printable )
>>> {
>>> printable.print( stream );
>>> return stream;
>>> }

>>
>> 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!

>
> 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?


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:rint ) >::value
> , std:stream &
>> ::type

> operator<<( std:stream &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:stream &
> 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



Reply With Quote
  #10 (permalink)  
Old 06-20-2012, 10:35 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Bo Persson wrote:

> Gerhard Fiedler skrev 2012-06-20 14:51:
>> Gerhard Fiedler wrote:
>>
>>> Luca Risolia wrote:
>>>
>>>> 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:rint)>::value, int>::type= 0 >
>>>> std:stream &operator<<( std:stream &stream,
>>>> Printable const &printable )
>>>> {
>>>> printable.print( stream );
>>>> return stream;
>>>> }
>>>
>>> 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!

>>
>> 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?

>
> 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:rint ) >::value
>> , std:stream &
>>> ::type

>> operator<<( std:stream &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:stream &
>> 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.


Thanks for the confirmation.

Gerhard
Reply With Quote
  #11 (permalink)  
Old 06-21-2012, 12:36 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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:stream &operator<<( std:stream &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
Reply With Quote
  #12 (permalink)  
Old 06-21-2012, 12:54 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

Luca Risolia wrote:

> 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:rint)>::value, int>::type= 0 >
> std:stream &operator<<( std:stream &stream,
> Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }


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:rint)
>::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
Reply With Quote
  #13 (permalink)  
Old 06-21-2012, 12:59 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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
Reply With Quote
  #14 (permalink)  
Old 06-21-2012, 03:02 PM
cartec69@gmail.com
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

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/2...ions-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:rint) );
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: stream&>::type
operator<<( std:stream &stream, Printable const &printable )
{
printable.print( stream );
return stream;
}

class MyClass
{
public:
MyClass( char const *val ) : str( val ) {}
void print( std: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; };
Reply With Quote
  #15 (permalink)  
Old 06-21-2012, 08:23 PM
Gerhard Fiedler
Guest
 
Posts: n/a
Default Re: Generic ostream operator<<?

cartec69@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/2...ions-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:rint) );
> 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: stream&>::type
> operator<<( std:stream &stream, Printable const &printable )
> {
> printable.print( stream );
> return stream;
> }
>
> class MyClass
> {
> public:
> MyClass( char const *val ) : str( val ) {}
> void print( std: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: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
Reply With Quote
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off




All times are GMT. The time now is 07:43 AM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.