6

So If I have something like this

template<typename... Args >
class tuple_class
{
  public:
  std::tuple<Args...> tup;

/*I left out the other functions */
};

I want to overload the operator<< so that it will recursively print the tuple when called on the class.

ex.

auto a = tuple_class(1, 2 ,3);
std::cout << a << endl;

would hopefully print '123'

Ive seen other examples of tuple printers but I can't apply it to my class without having a bunch of trouble

I think I should start with a member function like this

  template<typename... Args>
  friend std::ostream& operator<<(std::ostream& os, const my_tuple<Args...> &m);

and then the actual function outside the class

template<typename... Args>
std::ostream& operator<<(std::ostream& os, const my_tuple<Args...> &m)
{
   os << "SOMETHING" << std::endl;
   return os;
}

That actually worked when I call the << operator on my class. But I have no clue how to make it actually print the tuple.

Any help would be appreciated

user2770808
  • 347
  • 3
  • 14
  • 1
    You need to recursively unroll the variadic template through partial specialization. See [this question](http://stackoverflow.com/questions/7124969/recursive-variadic-template-to-print-out-the-contents-of-a-parameter-pack). –  May 16 '16 at 19:37

2 Answers2

2

To build solution I used tuple print code from cppreference mentioned here this. Rest of the code is glue to keep things together. Here I put working sample.

#include <tuple>
#include <iostream>
#include <string>

// tuple printer
template<class Tuple, std::size_t N>
struct TuplePrinter {
    static std::ostream& print(std::ostream& os, const Tuple& t)
    {
        TuplePrinter<Tuple, N - 1>::print(os, t);
        os << ", " << std::get<N - 1>(t);
        return os;
    }
};

template<class Tuple>
struct TuplePrinter<Tuple, 1> {
    static std::ostream& print(std::ostream& os, const Tuple& t)
    {
        os << std::get<0>(t);
        return os;
    }
};

template<class... Args>
std::ostream& print(std::ostream& os, const std::tuple<Args...>& t)
{
    os << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(os, t);
    os << ")\n";
    return os;
}


// class to keep tuple inside
template<typename... Args>
class tuple_class {
    template<typename... Args2>
    friend std::ostream& operator<<(std::ostream& os, const tuple_class<Args2...> &m);

    std::tuple<Args...> tup;
public:
    tuple_class(Args&&... args) : tup(std::forward<Args>(args)...) {

    }
};

// usage of the printer
template<typename... Args>
std::ostream& operator<<(std::ostream& os, const tuple_class<Args...> &m) {
    print(os, m.tup);
    return os;
}



int main() {
    tuple_class<int,float,std::string> tc( 1,3.0f,"string" );
    std::cout << tc;
    return 0;
}
Community
  • 1
  • 1
LookAheadAtYourTypes
  • 1,629
  • 2
  • 20
  • 35
  • Thanks for the response, when I try this I get 2 errors: error: cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’ os << std::get<0>(t); and error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ and ‘std::__tuple_element_t<0ul, – user2770808 May 16 '16 at 20:47
  • Could you provide me your exact version of compiler and also compiler flags you,be used? – LookAheadAtYourTypes May 17 '16 at 05:42
  • I fixed it had to do with the way I was building my tuple. Thank you! – user2770808 May 17 '16 at 20:05
0

If you can do without standard tuples, I propose the following simple (I hope so) solution.

#include <iostream>

template <typename ... Args >
class my_tuple;

template <typename A0, typename ... Args >
class my_tuple<A0, Args...>
 {
   private:

      A0                 elem;
      my_tuple<Args...>  next;

   public:

      my_tuple (const A0 & a0, const Args & ... args)
         : elem { a0 }, next { args ... }
       { }

      /*I left out the other functions */

      friend std::ostream& operator<< (std::ostream & os,
                                       const my_tuple<A0, Args...> & m)
       { return os << m.elem << m.next; }
 };

template <>
class my_tuple<>
 { 
   public:

      friend std::ostream& operator<< (std::ostream & os,
                                       const my_tuple<> &)
       { return os; }
 };

int main ()
 {
   my_tuple<int, float, long>  mt1 { 12, 23.4, 45L };
   my_tuple<int, int, int>     mt2 { 1, 2, 3 };

   std::cout << "my tuple 1 [" << mt1 << ']' << std::endl;
   std::cout << "my tuple 2 [" << mt2 << ']' << std::endl;

   return 0;
 }
max66
  • 65,235
  • 10
  • 71
  • 111