Define a template operator<< for iterables - c++

I'm able to define and use:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& container)
{
for (auto const& n : container)
os << n << ", ";
return os;
}
int main()
{
std::vector<int> data{0,1,2};
std::cout << data << '\n';
}
(demo)
But the definition of that operator doesn't depend on what kind of container I use. From there, I'd like to define a templated version:
template<class Iterable>
std::ostream& operator<<(std::ostream& os, Iterable const& iterable)
{
for (auto const& n : iterable)
os << n << ", ";
return os;
}
int main()
{
std::vector<int> data{0,1,2};
std::cout << data << '\n';
}
(demo)
This is where my compiler gets angry and verbosily reject it:
error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'char')
... with a lot of possible candidates.
Why is it not legal and how could I define such an operator?

As stated in this other StackOverflow question, How do I fix “ambiguous overload” error when overloading operator<< (templated)?
, when defining operator<<(std::ostream&, T) for all T, you overload it for types where an existing operator<< exists. Hence the ambiguous call:
os << n << ", ";
^-- recursively calls itself? or calls the overload provided by the Standard Library?
The solution is to use SFINAE to ensure you define your overload only for iterable types. Since the definition of the range-based for loop is based on begin and end, we can use it to discriminate what is an Iterable:
template<class Iterable, class = std::void_t<decltype(begin(std::declval<Iterable>()))>>
std::ostream& operator<<(std::ostream& os, Iterable const& iterable)
{
for (auto const& n : iterable)
os << n << ", ";
return os;
}
(demo)
Now, std::cout << data calls your version and std::cout << '\n' calls the build-in overload since the substitution fails for Iterable = char: begin(char) is not defined.

Related

c++ template specialization of template container

what i would do is like ...
template < template <typename ... > typename __Container, typename ... __Args >
ostream& operator<<(ostream& os, __Container<__Args ...> const& rhs){
stringstream ss;
int i = 0;
for (const auto& it : rhs)
ss << "idx[" << i << "] " << it << "\n";
return os << ss.str();
}
///
/// ... and something template specialization code
///
int main (){
std::vector<int> vec_data = { ... };
std::cout << vec_data << std::endl;
std::deque<int> dq_data = { ... };
std::cout << dq_data << std::endl;
std::map<std::string, double> map_data = { {}, {}, {}, ... };
std::cout << map_data << std::endl;
return 0;
}
in this example, deque and vector are not a problem, but when i tried to struggle to specialize std::map i dumped it. is there any possible way to do it?
Function templates can't be partially specialized, but can be overloaded:
template <typename ...P>
std::ostream &operator<<(std::ostream &os, const std::map<P...> &map)
But it's not the best idea, because you'd also have to specialize for std::multimap and std::unordered_[multi]map, and any non-standard containers you encounter in the future.
Instead you could create a function to print the single element, and overload it for std::pair (which is the element type of maps). Then call it from your operator.
There are more problems with the code:
Operators should only be overloaded where ADL can find them. Otherwise you won't be able to call them from some places (from any namespace that defines any operator<<; or from a template function defined above your operator).
Since the only suitable namespace here would be std, and adding declarations there is not allowed, you shouldn't create such operator in the first place. Write a function instead.
Identifiers containing __ or starting with _[A-Z] are reserved, don't use them.
The operator<< should accept any basic_ostream<...> to support wide streams.
stringstream should be ostringstream, or removed altogether (print directly to the ostream).

Can I overload the insertion operator to take a templated-STL container? [duplicate]

This question already has answers here:
C++ print template container error (error: ambiguous overload for 'operator<<') understanding?
(4 answers)
Closed 3 years ago.
I have this example which is about STL containers so i'm reading about them, It gets so tedious for me to repeatedly use a range-for loop to print the content of a container. So I thought about overloading the insertion operator << thus I can write: std::cout << container << std::endl;.
template<class T>
std::ostream& operator<<(std::ostream& out, const std::list<T>& v) {
for (const auto& e : v)
out << e << ", ";
return out;
}
int main() {
std::list<int> vi{ 10, 24, 81, 57, 2019 };
vi.pop_back();
std::cout << vi << std::endl; // 10, 24, 81, 57,
std::deque<std::string> names{ "Hello", "STL Containers" };
std::cout << names << std::endl; // error here. Bacause I've not overloaded << to take a std::deque<T>
}
As you can see above I find it so comfortable to print a list of some type. The problem is I can only print a list but not other sort of container like a vector or deque...
So how can I overload << to take a container of type T<U> or Should I specialize it for all the containers?
In a real example Shouldn't I do that?
You could provide the following overload :
template <class...>
using void_t = void;
template <class... Args>
constexpr bool exists_t_v(){
return std::is_same<void_t<Args...>, void>::value;
}
template <class Container, class = std::enable_if<
exists_t_v<
decltype(std::begin(std::declval<Container>())),
decltype(std::end(std::declval<Container>()))
>()
>>
std::ostream& operator<<(std::ostream& os, Container&& container){
for(const auto& e : std::forward<Container>(container))
os << e << ',';
return os;
}
This will let any instance container of the type Container for which std::begin(container) and std::begin(container) are defined to use the overload.
One of the issues with solutions like these is std::string support as well as any type that already provide its own overload for which std::begin() and std::end() are defined.
I hope that is not possible, I tried to put iterators in the operator<< but even they require to have exact iterator type, this is the closest possible solution using ostream_iterator:
template<class T2, class T>
void showT(ostream&out, T b, T end){
out << '[';
copy(b, end, ostream_iterator<T2>{out, ", "});
out<<"]";
return;
};

Recursive vector template

I've written the following piece of code:
template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
os << "{";
for (auto i=v.begin(); i!=v.end(); ++i) {
os << *i << " ";
}
os << "}";
return os;
}
This works fine for regular vector<int> instances, but what I want to do is this:
vector<vector<int> > v={{1,2},{3,4}}
cout << v; // Should print {{1 2 } {3 4 } }
Instead, I get compilation errors (the following text, with a long list of candidates): test.cpp|212|error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::vector<std::vector<int> >')|
I'd have thought the templated function could be used twice, recursively. Am I wrong? If not, what gives? If so, is there some way to make this generic without duplicating code?
#include <iostream>
#include <vector>
template<class T, class A>
std::ostream& operator<<(std::ostream& os, const std::vector<T,A>& v) {
os << "{";
for(auto&&e:v)
os<<e<<" ";
os << "}";
return os;
}
int main(){
std::vector<int> v1{1,2,3};
std::cout<<v1<<"\n";
std::vector<std::vector<int>> v2{{1},{2,3}};
std::cout<<v2<<"\n";
}
the above compiles and runs. Fix your typos, or be careful what namespace you are working with. Overloading operators in anything but the current namespace or in an ADL related one tends to fail.

error: 'e' is not a class, namespace, or enumeration

I'm trying to overload operator << for printing only every two elements of STL containers. But I have an error during the compilation:
error: 'e' is not a class, namespace, or enumeration
And here is my code:
#include <iostream>
#include <vector>
template<typename T>
std::ostream& operator<<(std::ostream &out, T const &e){
for(e::iterator it = e.begin(); it != e.end(); it = it + 2){
out << *it << " ";
}
return out;
}
int main(){
std::vector<int> v;
for(int i= 0; i < 10; i++){
v.push_back(i);
}
std::cout << v;
return 0;
}
You have two issues here.
One is with e::iterator. You can't access a member type through an object, you need to use the type. Instead you should just use auto it = e.begin(). If you can't use C++11, then you'll need to use
typename T::const_iterator it = e.begin()
The typename is needed because the name is dependent on a template parameter, and the const_iterator is needed instead of just iterator, because the parameter is marked const.
However, your more egregious error is in making this overload in the first place.
template<typename T>
std::ostream& operator<<(std::ostream &out, T const &e){
This declares an overload for std::ostream output for any type. This is sure to cause you a headache, and, sure enough, if you fix the first error, you get an ambiguous function call error when trying to output " ":
main.cpp:7:20: error: use of overloaded operator '<<' is ambiguous (with operand types '__ostream_type' (aka 'basic_ostream<char, std::char_traits<char> >') and 'const char [2]')
out << *it << " ";
~~~~~~~~~~ ^ ~~~
If you really want to make this work with every standard library container, I guess you check if something like T::iterator exists, and only have your overload enabled if that's true. Something like this:
template<typename T, typename = typename T::iterator>
std::ostream& operator<<(std::ostream &out, T const &e){
for(auto it = e.begin(); it != e.end(); it = it + 2){
out << *it << " ";
}
return out;
}
Live demo

Print any c++11 array with a non-member ostream-overloaded function

Is there a way in C++11 to let the compiler determine the templates of a function parameter? So I want to print a C++11-Array with only one stream-operator-function for all types and do not want to define same stream-operator-overloads just for another array type:
ostream& operator<<(ostream& stream, const array<float, 3>& v)
{
stream << v[0] << ", " << v[1] << ", " << v[2];
return stream;
}
I have tried something like this:
ostream& operator<<(ostream& stream, const array<auto, 3>& v)
{
stream << v[0] << ", " << v[1] << ", " << v[2];
return stream;
}
or
ostream& operator<<(ostream& stream, const array<typename...>& v)
{
stream << v[0] << ", " << v[1] << ", " << v[2];
return stream;
}
but the compiler doesn't compile these alternatives. Is there another nice solution or do I really have to define each time an overloaded function for each type?
You'd need a function template parametrised by the array type:
template <typename T>
ostream& operator<<(ostream& stream, const array<T, 3>& v)
The template parameter can be deduced from the function argument, so normal usage of the operator is fine:
cout << array<float, 3>{{1,2,3}} << endl;
The size can also be a parameter, if you want to support arbitrary arrays
template <typename T, size_t N>
ostream& operator<<(ostream& stream, const array<T, N>& v)
Directly overloading operators in std types is generally a bad idea.
A thin wrapper that does the job, however, works well:
// `tuple_printer` takes a type and a size. The size is by default
// deduced from the type.
template<class Tuple, size_t size = std::tuple_size< std::decay_t<Tuple> >{}>
struct tuple_printer {
// not used:
using indexes = std::make_index_sequence<size>;
// all but the last index: (C++14, but easy to write in C++11)
using pre_indexes = std::make_index_sequence<size-1>;
// store a forwarding reference to the tuple-like data:
Tuple&& tuple;
// The operator<<. Forwards to other methods.
friend std::ostream& operator<<(std::ostream& stream, tuple_printer&& self) {
std::move(self).print_to(pre_indexes{}, stream, ',');
std::move(self).print_to(std::index_sequence<size-1>{}, stream);
return stream;
}
// printing with a separator:
template<size_t...Is, class X>
void print_to(std::index_sequence<Is...>,std::ostream& stream, X&& x)&& {
// indexes trick, plus array trick. Looks prettier in C++17:
int _[]={0,((void)(
stream << std::get<Is>(std::forward<Tuple>(tuple)) << x
),0)...};
(void)_;
}
// printing without a separator:
template<size_t...Is>
void print_to(std::index_sequence<Is...>,std::ostream& stream)&& {
int _[]={0,((void)(
stream << std::get<Is>(std::forward<Tuple>(tuple))
),0)...};
(void)_;
}
};
// specialization for empty tuples:
template<class Tuple>
struct tuple_printer<Tuple,0> {
Tuple&& tuple;
friend std::ostream& operator<<(std::ostream& stream, tuple_printer&& self) {
return stream;
}
};
// function that does the type deduction for you:
template<class Tuple>
tuple_printer<Tuple> print_tuple(Tuple&& t){return {std::forward<Tuple>(t)};}
live example
Use looks like:
std::cout << print_tuple(array) << '\n';
where we wrap our array (or other tuple-like) with a function call, which does the pretty-print handling for us when streamed to a stream.
As a bonus, the above works with std::tuple and std::array and std::pair.
Overloading operator<< (or any other function that is meant to be found through ADL) outside of the namespace of its arguments is quite problematic and will end up failing some time. Since you cannot add overloads to the std namespace, and assuming that array means std::array, I would recommend against overloading the operator altogether.
You can print the contents of any container that has iterators with a simple algorithm:
std::copy(c.begin(), c.end(), std::ostream_iterator<T>(std::cout, " "));
Improving the style of the printout (changing the separator and not having it after the last item) takes a bit more time, but you should be able to write a simple named function for that and call it from wherever you are calling operator<< now. Yes, it does have some syntactic overhead, yes you should do it.