How to create a default thread installation statement in C ++?

I have a class similar to boost :: any, since this is a template container class. I would like to have a method for writing the contained value to a string. However, if the contained type does not provide a stream insert operator, I would like my method to return some trigger by default rather than compile it. Below, as close as I came, and should clearly indicate what I'm trying to do:

namespace W { namespace hide { template <typename T> std::ostream& operator<<(std::ostream& out, const T& t) { return std::operator<<(out, typeid(T).name()); } } template <typename T> struct C { T t_; std::string ToString() const { using namespace hide; std::ostringstream oss; oss << t_; return oss.str(); } }; } 

This works very well, with some caveats. For example, if I want to actually provide an overloaded insert operator for a class, then this operator must either be in the same namespace as the class, or it must be in the W namespace so that it is read.

It also has problems with any type that the non-member std :: operator <<char and std :: string already has. If T is one of these types, then the line oss << t_ above becomes ambiguous. This can be circumvented by adding overloads for these types inside the W namespace, for example:

 std::ostream& operator << (std::ostream& out, const std::string& s) { return std::operator <<(out, s); } 

My question is: has anyone found a better method than this? Why should I add my own overloads for things like std :: string? Is it supported according to the standard, or am I using non-standard behavior? (I am testing g ++ 4.3.3)

+6
c ++ iostream overloading templates
source share
1 answer

Below is the code that, as I recall, I saw some time ago in the compiler build class. I thought it was especially smart (if not β€œclean”), so I held on to it.

From http://www.cs.colorado.edu/~main/a++/tree.h

  // If data of type T can be printed with the usual << operator, then // print<T>(out, p) will interpret *p as a T object and print its // value to out. Otherwise, a message is printed to out, indicating // that objects of type T are not printable. template<typename T> void print(std::ostream& out, const void* p) { // The first part of this code sets an enum value, is_printable, to // be 1 if the data type T can be printed with the usual << // operator. Otherwise, is_printable is set to zero. The programming // technique is based on a note from Herb Sutter at // http://www.gotw.ca/gotw/071.htm class object { public: object(T convert) { }; }; char operator << (std::ostream&, const object&); enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 }; // Notice that the boolean expression in the if-statement is known at // compile time, so that only one of the two output statements will be // compiled into object code. if (is_printable) out << *static_cast<const T*>(p); else out << "(value of type " << typeid(T).name() << " cannot be printed)"; } 

When you create your container object, hold the pointer to the print function for the variable:

 void (*printer)(std::ostream&, const void*); printer = print<T>; 

Then later use the printer () function to display the contained value, if possible.

Hope this helps.

+3
source share

All Articles