3

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.

Community
  • 1
  • 1
akim
  • 8,255
  • 3
  • 44
  • 60
  • 3
    http://stackoverflow.com/questions/6245735/pretty-print-stdtuple and here is an example with integer_sequence: http://en.cppreference.com/w/cpp/utility/integer_sequence – nosid May 05 '14 at 10:15
  • Just wanted to point out that the linked answer does not solve the clang compilation problem - it still fails. It's just another technique for printing the tuples. – Ivan Vergiliev May 06 '14 at 22:04

1 Answers1

1

You can read about the reason clang is not compiling it here: http://clang.llvm.org/compatibility.html#dep_lookup . It seems that clang's behaviour is standard-compliant.

To fix it, you can define operator<< in namespace std to make argument-dependent lookup work correctly. Actually this might be undefined behaviour, since it does not comply with the requirements for adding stuff to std.

Ivan Vergiliev
  • 3,771
  • 24
  • 23
  • Bummer, of course the problem is the `namespace` :( How could I have forgotten something so obvious. Thanks! – akim May 05 '14 at 11:29