Compile error when overloading operator<< with template arguments - c++

I'm trying to use the stl copy () to print the key-value pair in a map. The code is as follows:
#include <iterator>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
//compile error if I comment out "namespace std"
namespace std {
template<typename F, typename S>
ostream& operator<<(ostream& os, const pair<F,S>& p) {
return os << p.first << "\t" << p.second << endl;
}
}
int main() {
map<int, int> m;
fill_n(inserter(m, m.begin()), 10, make_pair(90,120));
copy(m.begin(), m.end(), ostream_iterator<pair<int,int> >(cout,"\n"));
}
I'm trying to overload operator<<. The problem is that the code won't compile unless I surround the definition of the overloaded operator<< with namespace std. I think it is due to the name lookup mechanism of C++, which I still have trouble understanding. Even if I define non-template version like this:
ostream& operator<<(ostream& os, const pair<int,int>& p) {
return os << p.first << "\t" << p.second << endl;
}
It still won't compile. Can anyone explain why?

Your problem is with argument-dependent name lookup (ADL). The compiler is searching for an implementation of operator<< in namespace std, as both ostream and pair are in that namespace. You should make a wrapper that forwards to operator<< from the correct namespace:
template<class T>
struct ostreamer {
ostreamer(const T& value) : reference(value) {}
const T& reference;
friend ostream& operator<<(ostream& stream, const ostreamer& value) {
return stream << value.reference;
}
};
Then just use ostream_iterator<ostreamer<pair<const int, int>>> instead of ostream_iterator<pair<int, int>>. Note that because ostreamer stores by reference and not by value, you can’t rely on the implicit conversion from pair<const int, int> to pair<int, int> anymore. You could change ostreamer to store by value, but as it is, it has no overhead, and I think it’s better to be explicit anyway.

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).

Overload for ostream on vectors throws error when using std::copy

I am wondering why the following fails to compile:
#include <vector>
#include <ostream>
#include <iterator>
#include <algorithm>
#include <iostream>
template <template <typename...> class Container, class T>
std::ostream& operator<<(std::ostream& oss, const Container<T>& c) {
oss << "[";
std::copy(std::cbegin(c), std::prev(std::cend(c)), std::ostream_iterator<T>(oss, ","));
return oss << (*std::crbegin(c)) << "]";
}
auto main() -> int {
std::vector<std::vector<unsigned>> data(5);
std::cout << data << std::endl;
return 0;
}
http://coliru.stacked-crooked.com/a/431617423f92ba4e
It compiles fine when I do one of the following:
Remove the line with std::copy
Change the vector to be a one-dimensional vector (std::vector<unsigned> data(5) for example).
What is it about std::copy that is causing the error?
Debugging with clion, this is the type of the nested vector that gets printed in the crbegin line:
Because your operator<< is not visible to std entities.
Note std::ostream_iterator<T> outputs values as if through operator<<, and according to [temp.dep.res]/1:
In resolving dependent names, names from the following sources are
considered:
Declarations that are visible at the point of definition of the template.
Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point])
and from the definition context.
... your operator<< is neither visible at the point of definition of std::ostream_iterator<T>, nor in the namespace std, so the operator<< used in std::ostream_iterator<T> cannot be correctly resolved.
Your operator<< is not visible to std::ostream_iterator, so it can't call your operator<< on elements of the input container. Just use a manual loop instead, then it will work as expected.
Also, std::prev(std::cend(c)) and *(c.crbegin()) are undefined when the container is empty, so watch out for that.
Also, std::vector (like most other standard containers) has more than 1 template parameter, so use typename... Ts instead of class T in your operator's template parameters.
Try this:
#include <vector>
#include <iterator>
#include <iostream>
template < template<typename...> class Container, typename... Ts>
std::ostream& operator<<(std::ostream& oss, const Container<Ts...>& c) {
oss << "[";
if (!c.empty()) { // use std::empty() in C++17 and later
auto last = std::prev(std::cend(c));
/*
using value_type = typename Container<Ts...>::value_type;
std::copy(std::cbegin(c), last, std::ostream_iterator<value_type>(oss, ","));
*/
for(auto iter = std::cbegin(c); iter != last; ++iter)
oss << *iter << ",";
oss << *last;
}
return oss << "]";
}
int main() {
std::vector<std::vector<unsigned>> data(5);
std::cout << data << std::endl;
return 0;
}
Output
[[],[],[],[],[]]
Live Demo
Here's an experiment that will lead you toward the answer:
#include <vector>
#include <ostream>
#include <iterator>
#include <algorithm>
#include <iostream>
namespace std {
template <template <typename...> class Container, class T>
std::ostream& operator<<(std::ostream& oss, const Container<T>& c) {
oss << "[";
std::copy(std::cbegin(c), std::prev(std::cend(c)), std::ostream_iterator<T>(oss, ","));
return oss << (*std::crbegin(c)) << "]";
}
}
int main() {
std::vector<unsigned> t{ 1, 2, 3 };
std::vector<std::vector<unsigned>> data(5, t);
std::cout << data << std::endl;
return 0;
}
Sidenote: without defining t, it'll compile (i.e., your operator<< will be found when needed), but if you try to run it, it'll crash--trying to use std::prev(std::cend(c)) on an empty container isn't going to end well.
Of course, this does violate the requirements of the standard (defining your operator<< inside namespace std like this isn't allowed), but at least with typical compilers, the name will now be found so the code will compile.

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.

Best way to specialise operator<< for std::ostream and std::vector with generic template functions?

I am having trouble with the two-phase look-up as specified by the standard and (correctly) implemented by clang in connection with an overload of operator<< for std::ostream and std::vector.
Consider a very generic template function which shifts its argument into a stream (really useful only with recursion, but the simple example is enough to trigger the problem):
// generic.h
template<typename Stream, typename Arg>
void shift(Stream& s, Arg& arg) { s << arg; }
This generic.h may be used throughout a project. Then in some other file, we want to output a std::vector, so we define an overload
// vector.h
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v) {
for(auto const& elem : v) { s << elem << ", "; }
return s;
}
And the main file, we firstly (indirectly) use the generic.h and then, due to some other include, the vector overload:
// main.cpp
#include "generic.h"
#include "vector.h"
int main() {
std::vector<int> v{1,2,3,4,5};
shift(std::cout, v);
}
This code is accepted by GCC (5.4.0) and ICC (16.0), but clang complains call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup.
The annoying thing is that clang is right and I’d like to fix this in my code. There are as far as I can see three options:
Move the definition of operator<< before shift(). This has the disadvantage that when including some (possibly other) files which indirectly include generic.h and vector.h, one would also have to take care to order them correctly.
Use a custom namespace, import everything needed from std into that namespace and define the operator on the new-namespace classes inside that namespace, so that ADL can find it.
Define operator<< in the std namespace. I think this is undefined behaviour.
Did I miss any option? What would be the best way in general to define overloads for functions of std-only classes (the issue does not exist if I want to shift NS::MyClass, since then I can just define the operator in NS).
Don't overload operators for types you don't control, such as:
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v);
Instead create a tiny adaptor class and define the operator for that, for example:
template<typename T> struct PrintableVector {
std::vector<T> const* vec;
}
template<typename T>
std::ostream& operator<<(std::ostream& s, PrintableVector<T> v) {
for(auto const& elem : *v.vec) { s << elem << ", "; }
return s;
}
That can be used like:
shift(std::cout, PrintableVector<int>{&v});
You can put the adaptor in whatever namespace you like, and put the overloaded operator in the same namespace so it can be found by ADL.
That avoids lookup problems, doesn't require adding anything to namespace std, and doesn't try to uniquely define what it means to print a vector<int> (which might cause problems in other parts of the program if some other code assumes vectors are not printable, or tries to define its own overloads for them).
I followed Jonathan’s advice and used a wrapper Printable<> to define the operator<<. By making this wrapper also implicitly-convertible to the original type, I can handle both cases where only Printable<T> is printable as well as those were also T itself was printable. Code as follows:
template<typename T>
struct Printable {
T const& ref;
Printable(T const& ref) : ref(ref) { }
operator T const& () { return ref; }
};
template<typename T>
Printable<T> printable(T const& in) { return Printable<T>(in); }
template<typename Stream, typename Arg>
void shift(Stream& s, Arg& arg) {
s << printable(arg);
}
#include <iostream>
#include <vector>
std::ostream& operator<<(std::ostream& out, Printable<std::vector<int> > const& v) {
for(auto const& elem : v.ref) { s << elem << ", "; }
return s;
}
struct MyClass { };
std::ostream& operator<<(std::ostream& s, MyClass const& m) {
return s << "MyClass\n";
}
int main() {
std::vector<int> v{1,2,3};
MyClass m;
shift(std::cout, v);
shift(std::cout, m);
}
This has the advantage that at the point of use in the call to shift(), I don’t have to care what sort of type my variable has. Only in the definition of operator<< for classes I have to be careful as well as when using such an operator.

Overloading << for type inside another class

I have a typedef inside a class and I would like to overload the operator<< for it to be able to print it in ostream. However, the compiler cannot find the overloaded operator. How can I declare it so that it works?
#include <iostream>
#include <set>
using namespace std;
template <class C>
struct K {
typedef std::set<C> Cset;
Cset s;
// and many more elements here
friend ostream& operator<<(ostream& oo, const Cset& ss){
typename Cset::const_iterator it=ss.begin();
oo << "[";
for(; it!=ss.end(); ++it) oo << (*it) << ",";
oo << "]";
return oo;
}
void DoSomething(){
// do something complicated here
cout << s << endl;
// do something complicated here
}
};
int main(){
K <int> k;
k.s.insert(5);
k.s.insert(3);
k.DoSomething();
}
gcc version 4.4.5 20101112 (Red Hat 4.4.5-2) (GCC)
When a friend function is defined inline and there is no forward declaration outside the class, it is only found by ADL. However, your overload will never be found by ADL as it does not involve K arguments (note that K<int>::CSet is a typedef for std::set<C>).
Just for completeness: final version of the code for operator<<:
template <class T, class U>
std::ostream& operator<<(std::ostream& oo, const std::set <T,U> & ss){
typename std::set <T,U> ::const_iterator it=ss.begin();
oo << "[";
if(it!=ss.end()) oo << (*it++);
while(it!=ss.end()) oo << "," << (*it++);
oo << "]";
return oo;
}