There are several proposals on how to print a tuple
. The snippet below reproduces the answer of Kenny from overloading operator << for std::tuple - possible simplications?.
#include <iostream>
#include <tuple>
#include <type_traits>
// template <typename... T>
// std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& tup);
template <size_t n, typename... T>
typename std::enable_if<(n >= sizeof...(T))>::type
print_tuple(std::ostream&, const std::tuple<T...>&)
{}
template <size_t n, typename... T>
typename std::enable_if<(n < sizeof...(T))>::type
print_tuple(std::ostream& os, const std::tuple<T...>& tup)
{
if (n != 0)
os << ", ";
os << std::get<n>(tup);
print_tuple<n+1>(os, tup);
}
template <typename... T>
std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& tup)
{
os << "[";
print_tuple<0>(os, tup);
return os << "]";
}
int
main()
{
auto t = std::make_tuple(1, std::make_tuple(2, 3));
std::cout << t << std::endl;
}
My problem is that it does not work properly with clang (3.5) with tuples of tuples (gcc 4.9 is happy though):
clang++-mp-3.5 -std=c++11 print.cc
print.cc:19:10: error: call to function 'operator<<' that is neither visible in the
template definition nor found by argument-dependent lookup
os << std::get<n>(tup);
^
print.cc:20:7: note: in instantiation of function template specialization
'print_tuple<1, int, std::__1::tuple<int, int> >' requested here
print_tuple<n+1>(os, tup);
^
print.cc:27:7: note: in instantiation of function template specialization
'print_tuple<0, int, std::__1::tuple<int, int> >' requested here
print_tuple<0>(os, tup);
^
print.cc:35:19: note: in instantiation of function template specialization
'operator<<<int, std::__1::tuple<int, int> >' requested here
std::cout << t << std::endl;
^
print.cc:24:19: note: 'operator<<' should be declared prior to the call site
std::ostream& operator<<(std::ostream& os, const std::tuple<T...>& tup)
^
If I uncomment the forward declaration for operator<<
on tuples, it works. However it does not fit nicely in a framework where you don't force the definition of operator<<
for tuples, but leave to the user the choice to bind it to print_tuple
: she has to forward declare the function before including the header that defines print_tuple
.
I don't understand well what's going on here: in a template, clang appears to refuse to use functions that are defined after the point of the definition of the template, but before the point of instantiation. I would have thought that what matters is the point of instantiation.
Conversely, why does GCC accept? Is one of the compilers wrong? What would be the nicest way to leave to the user the choice of defining this operator<<
, and have it work properly recursively?
Thanks.