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<< before shift(). has disadvantage when including (possibly other) files indirectly include generic.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<< in std 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