c++ - Best way to specialise operator<< for std::ostream and std::vector with generic template functions? -
i having trouble two-phase look-up specified standard , (correctly) implemented clang in connection overload of operator<<
std::ostream
, std::vector
.
consider generic template function shifts argument stream (really useful recursion, simple example enough trigger problem):
// generic.h template<typename stream, typename arg> void shift(stream& s, arg& arg) { s << arg; }
this generic.h may used throughout project. in other file, want output std::vector
, define 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 main file, firstly (indirectly) use generic.h
, then, due other include, 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 accepted gcc (5.4.0) , icc (16.0), clang complains call function 'operator<<' neither visible in template definition nor found argument-dependent lookup
.
the annoying thing clang right , i’d fix in code. there far can see 3 options:
move definition of
operator<<
beforeshift()
. has disadvantage when including (possibly other) files indirectly includegeneric.h
,vector.h
, 1 have take care order them correctly.use custom namespace, import needed
std
namespace , define operator on new-namespace classes inside namespace, adl can find it.define
operator<<
instd
namespace. think undefined behaviour.
did miss option? best way in general define overloads functions of std
-only classes (the issue not exist if want shift ns::myclass
, since can define operator in ns
).
don't overload operators types don't control, such as:
std::ostream& operator<<(std::ostream& s, std::vector<int> const& v);
instead create tiny adaptor class , define operator that, 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 used like:
shift(std::cout, printablevector<int>{&v});
you can put adaptor in whatever namespace like, , put overloaded operator in same namespace can found adl.
that avoids lookup problems, doesn't require adding namespace std
, , doesn't try uniquely define means print vector<int>
(which might cause problems in other parts of program if other code assumes vectors not printable, or tries define own overloads them).
Comments
Post a Comment