As a template for the << operator for ostream

The following will not compile for me. I have no ideas ... Any help?

 template<> inline std::ostream& operator<< <const std::map<std::string, std::string> > (std::ostream& stream, const std::map<std::string, std::string>& some_map) { return stream; } 

g ++ gives me the following error:

error: expected initializer to '<' token

Edit: 1 Good, since everyone is telling me to overload, let me give you an example that does not make sense to overload. What if I have this:

 template <typename T> inline std::ostream& operator<<(std::ostream& stream, const T& something) { stream << something.toString(); return stream; } class Foo { public: Foo(std::string s) { name = s; } std::string toString() const { return name; } private: std::string name; }; class Bar { public: Bar(int i) { val = i; } std::string toString() const { std::ostringstream stream; stream << val; return stream.str(); } private: int val; }; int main(int, char**) { Foo foo("hey"); Bar bar(2); std::cout << foo << std::endl; std::cout << bar << std::endl; return 0; } 

Now that won't work either.

I just want to avoid overloading the <<<operator over and over again using the pattern as above. It seems to be possible. I would like to know if this is so, and if so, how?

In this case, overloading both Foo and Bar to do the same would be a waste, so I try to avoid it.

Edit: 2 Well, it seems like they misunderstood me. Here is another attempt to clarify:

 template <typename T> std::ostream& operator<<(ostream& stream, const T& t) { for(typename T::const_iterator i = t.begin(), end = t.end(); i != end; ++i) { stream << *i; } return stream; } int main(int, char**) { set<int> foo; list<string> bar; vector<double> baz; cout << foo << " " bar << " " << baz << endl; }; 

The code above will not work for you. Complains of ambiguity. But this seems like the best solution for printing containers. If I did this with overload, I would have to write a version of the <<operator for each container / data combination, which would lead to ridiculous code duplication.

+3
source share
3 answers

This does not have to be a template function.

 std::ostream & operator<<(std::ostream & stream, const std::map<std::string, std::string> & some_map) { return stream; } 

Edit

Regarding my comment on writing Java in C ++ (and, unfortunately, if that sounded rude, I was not going to be vague). Tell me if this does not help you. Instead of writing the "toString" method first, simply overload the <start with statement. The function is almost identical. Then you can write a nonStation toString function that will automatically work with all your classes, for example:

 #include <sstream> #include <string> template<typename T> std::string toString(const T & val) { std::ostringstream ostr; ostr << val; return ostr.str(); } 

Edit 2

Here is my alternative if you still insist on doing it your own way. Make all your classes with the toString method inherit from the abstract class using the virtual toString method, then write a single <<statement to handle all of them.

 class Stringifiable { public: virtual std::string toString() const = 0; }; std::ostream & operator<<(std::ostream & ostr, const Stringifiable& something) { return ostr << something.toString(); } 

Now the compiler will select your overload over the templates.

+5
source

You can use SFINAE to remove template overloads for reasons. Note that this should be part of the function signature. So you can use boost :: enable_if:

 template < typename T > typename boost::enable_if< meta_function_to_check_for_concept<T>, std::ostream&>::type operator << (std::ostream & out, T const& t) { ... } 

If you do not, your template will try to match almost everything and explode for every use <<this does not match the concept you are trying to match.

Your example is a little far-fetched and may not lend itself to this answer, but there are situations in which it is justified. Here's how to do it.

+3
source

In Crazy Eddie's comment, he mentions SFINAE. Now C ++ 11 has an embedded system. If all types come from the same base class, this is pretty simple. Here is a more complete example using C ++ 11:

 #include <type_traits> #include <iostream> #include <ostream> class MyBaseType {}; class MyClass : MyBaseType {}; class MyOtherClass : MyBaseType {}; class SomeType {}; template <typename T> typename std::enable_if<std::is_base_of<MyBaseType,T>::value,std::ostream&>::type operator<<(std::ostream& out, const T& x) { out << 1; } int main() { MyBaseType x; MyClass y; MyOtherClass z; SomeType i; std::cout << x << y << z; // success! std::cout << i; // compile-time failure! } 
0
source

Source: https://habr.com/ru/post/908251/


All Articles