Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

writing template for operator<< for any vector

I'm trying to write a template operator for any iterable container. Getting a strange error:

#include <iostream>

template <typename C>
std::ostream& operator<<(std::ostream& os, const C& c) {
  os << "[";
  for (const auto& v : c) {
    os << v << " ";
  }
  os << "]";
  return os;
}

vec.cc:5:6: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::ostream' (aka 'basic_ostream') and 'const char [2]') os << "["; ~~ ^ ~~~

Why this error? And how do I achieve what I want?

like image 742
MK. Avatar asked Jul 12 '17 19:07

MK.


2 Answers

Adding

template <typename C>
std::ostream& operator<<(std::ostream& os, const C& c) {
  os << "[";
  for (const auto& v : c) {
    os << v << " ";
  }
  os << "]";
  return os;
}

Conflicts with the other global overloads of operator <<.

To fix this we can constrain your template to any vector instead of any type using

template <typename C>
std::ostream& operator<<(std::ostream& os, const std::vector<C>& c) {
  os << "[";
  for (const auto& v : c) {
    os << v << " ";
  }
  os << "]";
  return os;
}
like image 140
NathanOliver Avatar answered Sep 28 '22 07:09

NathanOliver


At this line:

os << "[";

The compiler finds two valid functions: the STL's and yours.

You need to be a bit more specific in your template declaration in order to resolve the conflict:

template <typename C>
std::ostream& operator<<(std::ostream& os, const std::vector<C>& c) {
  ...

Expanding this to containers in general would require a bit of finagling with std::enable_if<> that will probably just confuse you further. I recommend you just add an overload for each type of container you want to support.

Edit: Also, overriding ostream << T, for types you don't own is generally a bad idea as it will eventually cause conflicts.

like image 36
Frank Avatar answered Sep 28 '22 06:09

Frank