I have a set of templates/functions that allow me to print a tuple/pair assuming that each type in the tuple/pair has operator<<
defined for it. Unfortunately, due to 17.4.3.1, it is illegal to add my operator<<
overloads to std
. Is there another way to get ADL to find my operator<<
? If not, is there any actual harm in wrapping my overload in namespace std{}
?
The code for anyone interested: (I'm using gcc-4.5)
namespace tuples {
using ::std::tuple;
using ::std::make_tuple;
using ::std::get;
namespace detail {
template< typename...args >
size_t size( tuple<args...> const& )
{
return sizeof...(args);
};
template<size_t N>
struct for_each_ri_impl
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
for_each_ri_impl<N-1>()(func, arg );
func( get<N>( arg ), size(arg) - N - 1 );
}
};
template<>
struct for_each_ri_impl<0>
{
template<typename Func, typename Tuple>
void operator()(Func func, Tuple const& arg)
{
func( get<0>( arg ), size(arg) - 1 );
}
};
}//detail
template<typename Func, typename ... Args>
void for_each_ri( tuple<Args...>const& tup, Func func )
{
detail::for_each_ri_impl< sizeof...(Args)-1>()( func, tup );
}
struct printer {
std::ostream& out;
const std::string& str;
explicit printer( std::ostream& out=std::cout, std::string const& str="," ) : out(out), str(str) { }
template<typename T>void operator()(T const&t, size_t i=-1) const { out<<t; if(i) out<<str; }
};
//Should this next line go into namespace std? Is there another way?
template<typename ... Args>
std::ostream& operator<<(std::ostream& out, std::tuple< Args... > const& tup)
{
out << '[';
tuples::for_each_ri( tup, tuples::printer(out,", ") );
return out << ']';
}
} //tuples
//Edits --
int main()
{
using namespace std;
cout<<make_tuple(1,'a',"Hello")<<endl;
return 0;
}
Compiling the above yields:
test.cpp: In function 'int main()':
test.cpp:69:31: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream&&' > /opt/local/include/gcc45/c++/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits, _Tp = std::tuple]'
Put your own light wrapper class around it and then overload operator<< to use that. However beware that even if your light wrapper has an implicit constructor you will probably still need to use it explicitly when you pass it to operator<<
This is an outline as I'm not sure exactly how to do it with variadic templates although it should be possible. You can easily implement several versions though with 1, 2, 3, etc.parameters, eg: