Writing template for operator << for any vector

I am trying to write a template statement for any iterative 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.cccc ::: error: using the overloaded operator '<<is ambiguous (with operand types' std :: ostream' (aka 'basic_ostream') and 'const char [2]') os <"["; ~~ ^ ~~~

Why is this a mistake? And how can I achieve what I want?

+4
source share
7 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 other global overloads operator << .

To fix this, we can limit your template to any vector, not 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;
}
+8

:

os << "[";

: STL .

, :

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

std::enable_if<>, , , . , .

: , ostream << T , , , .

+4

, << std::ostream& .

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

os << "[", operator<< ; . operator<<, , operator<<.

- , print_collection:

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

operator<<, . :

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;
}

, operator<< std::vector, .

, , operator<<, . - :

template <typename Iter>
class Range {
    Iter begin_;
    Iter end_;

public:
    Range() = default;
    Range(Iter begin, Iter end)
        : begin_{ begin }
        , end_{ end }
    {}

    auto begin() const { return begin_; }
    auto end() const { return end_; }
};

template <typename Iter>
auto range(Iter begin, Iter end) {
    return Range<Iter>{ begin, end };
}

template <typename C>
auto range(const C& collection) {
    return range(std::begin(collection), std::end(collection));
}

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

:

std::vector<int> vec = ...;
std::cout << range(vec);
+3

, operator<< . const char[2].

, , - begin() end()

#include <iostream>
#include <vector>

using std::cout;
using std::endl;

template <typename Container,
          std::enable_if_t<std::is_same<
            decltype(std::declval<Container>().begin()),
            decltype(std::declval<Container>().begin())>::value>* = nullptr>
std::ostream& operator<<(std::ostream& os, const Container& container) {
    os << "[";
    for (const auto& ele : container) {
        os << ele << " ";
    }
    os << "]";
    return os;
}

int main() {
    auto vec = std::vector<int>{1, 2, 3};
    cout << vec << endl;
}
+3

, < , ++.

SFINAE, - :

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

,

+2

, os << "[" .

, , SFINAE , begin().

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

- , operator<< std::ostream, .

, , :

std::ostream& operator<<(std::ostream&, const char*);

typename C = const char*.

, (, operator<<), , .

, ( , . . ).

, , (std::vector<T>, std::list<T> ..). , , , .

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

, ++ 11 - .

, , .

, , , , . std::array, .

0
source

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


All Articles