Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Error while trying to overload operator << for all std container printing, why?

I am trying to build an operator << overload to print all the standard library container types. So far, the overload works well, but when I use it in a generic program, it breaks when I try to print a simple std::string. In fact, this program:

#include <iostream>
#include <utility>
#include <vector>
#include <map>
#include <string>

// Helper Function to Print Test Containers (Vector and Map)
template <typename T, typename U>
inline std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p) {
    out << "[" << p.first << ", " << p.second << "]";
    return out;
} 

template <template <typename, typename...> class ContainerType, typename 
ValueType, typename... Args>
std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
    for (const auto& v : c) {
        os << v << ' ';
    }
  return os;
}

int main()
 {
  std::vector <int> v = { 1,2,3 };
  std::cout << v;

  std::map <int,int> m = { { 1, 1} , { 2, 2 }, { 3, 3 } };
  std::cout << m;

  std::string s = "Test";
  std::cout << s;
 }

Gives me this error:

prove.cpp: In function ‘int main()’:
prove.cpp:32:13: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’})
   32 |   std::cout << s;
      |   ~~~~~~~~~ ^~ ~
      |        |       |
      |        |       std::string {aka std::__cxx11::basic_string<char>}
      |        std::ostream {aka std::basic_ostream<char>}
prove.cpp:16:15: note: candidate: ‘std::ostream& operator<<(std::ostream&, const ContainerType<ValueType, Args ...>&) [with ContainerType = std::__cxx11::basic_string; ValueType = char; Args = {std::char_traits<char>, std::allocator<char>}; std::ostream = std::basic_ostream<char>]’
   16 | std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
      |               ^~~~~~~~
In file included from /usr/include/c++/9/string:55,
                 from /usr/include/c++/9/bits/locale_classes.h:40,
                 from /usr/include/c++/9/bits/ios_base.h:41,
                 from /usr/include/c++/9/ios:42,
                 from /usr/include/c++/9/ostream:38,
                 from /usr/include/c++/9/iostream:39,
                 from prove.cpp:1:
/usr/include/c++/9/bits/basic_string.h:6419:5: note: candidate: ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
 6419 |     operator<<(basic_ostream<_CharT, _Traits>& __os,
      |     ^~~~~~~~

I think that the problem is due to the fact that this overload is used to print also simple std::string objects, but I didn’t find any suitable way to solve this so far. Any help? thanks.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The issue is that your << is too generic. It matches std::cout << some_string; and potentially other types for which there is already a << overload. The solution is to not provide overloads for types you do not own (unless it is explicitly permitted).

With minimal changes you can refactor your << to be a named function, then write a wrapper:

template <typename T>
struct my_print {
     T& t;
};
tempalte <typename T>
std::ostream& operator<<(std::ostream& out,const my_print<T>& mp) {
    // call your named funtion template
    do_the_printing(out,mp);
    return out;
}

The caveat is that you need to explicitly create the instance:

std::cout << my_print(some_stl_container);

Of course you can also let your function template print directly and call it like this

do_the_print(std::cout,some_stl_container);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading