I use the following code to print generic C++ containers and exclude strings (thanks to this SO answer).
#include <iostream>
#include <vector>
template <typename T,
template <typename ELEM, typename ALLOC = std::allocator<ELEM>>
class Container>
std::ostream &operator<<(std::ostream &out, const Container<T> &container) {
out << "[";
bool first = true;
for (const auto &elem : container) {
if (first)
first = false;
else
out << ", ";
out << elem;
}
return out << "]";
}
int main() {
std::vector<std::vector<int>> v{{1, 2}, {3, 4}};
std::cout << v << "\n";
return 0;
}
Which prints the 2d vector correctly
[[1, 2], [3, 4]]
And does not mess with outputting strings. Is there a cleaner (concept-based?) way to write the template in C++20 or C++23?
With concepts, you might require only container/range types and discard string-like types, something like:
template <typename Container>
requires std::ranges::input_range<const Container>
&& (!std::convertible_to<const Container, std::string_view>)
std::ostream &operator<<(std::ostream &out, const Container& container)
{
out << "[";
const char* sep = "";
for (const auto &elem : container) {
out << sep << elem;
sep = ", ";
}
return out << "]";
}
With the caveats that generic template should involve at least one user type. Else it might conflict with possible future operator<<
for std (or other library) containers...