//  tr1::tuple



#include <tuple>
using std::tr1::tuple;

tuple<> none;                   // holds no elements
tuple<int> one;                 // holds one element, of type int

int i; double d;
tuple<int&, const double&>
    two(i, d);                  // holds two elements, one of
                                // type reference to int and one
                                // of type reference to const double
tuple<int, int, int, int, int,
  int, int, int, int, int> ten; // holds ten elements, all of type int



//  implementation dependent upper limit: N==10
//
//  get returns a reference to an element (may be modified)
//  tuple_size, tuple_element





//  create tuple

#include <utility>
#include <tuple>
using std::tr1::tuple; using std::pair;

class C
{
public:
  C() : val(0) {}
  C(int i) : val(i) {}
private:
  int val;
};

tuple<> t0;                 // default constructor
tuple<int> t1;              // default constructor; element
                            // not initialized
tuple<int> t2(3);           // element initialized to 3
tuple<C> t3;                // element initialized to C()
tuple<C> t4(C(1));          // element initialized to C(1)
tuple<C, C> t5(1, 2);       // first element initialized to C(1)
                            // second element initialized to C(2)
tuple<double> t6(t2);       // element initialized to 3.0
pair<int, int> p0(3, 4);    // first element initialized to 3
                            // second element initialized to 4
tuple<C, C> t7(p0);         // first element initialized to C(3)
                            // second element initialized to C(4)




//  make_tuple


#include <tuple>
#include <typeinfo>
#include <iostream>
using std::tr1::tuple; using std::tr1::make_tuple;

template <class T> void show_type(T)
{
    std::cout << typeid(T).name() << "\n\n";
}

int main()
{
    int i = 3;
    int& j = i;
    show_type(make_tuple());        // returns tuple<>
    show_type(make_tuple(1, 3.14)); // returns tuple<int,double>
    show_type(make_tuple(i, j));    // returns tuple<int,int>
    return 0;
}


//  make_tuple() does not distinguish between ref and value
//  for references use tr1::functional

#include <tuple>
#include <functional>           // for ref, cref
using std::tr1::make_tuple;
using std::tr1::ref; using std::tr1::cref;

void test()
{
    int i = 17;
    int j = 3;
    make_tuple(ref(i),cref(j)); // returns tuple<int&, const int&>
                                // first element is reference to i
                                // second element is reference to j
}


//  tie returns a tupple with references
//  ignore tells not to use operator=()

#include <tuple>
#include <iostream>
using std::tr1::make_tuple; using std::tr1::tie;
using std::tr1::ignore;

int i = 1;
int j = 2;
int k = 3;

void show()
{
  std::cout << i << ' ' << j << ' ' << k << '\n';
}

int main()
{
  show();       // 1 2 3
  tie(i, ignore, k) = make_tuple(5, 6, 7);
  show();       // 5 2 7
  return 0;
}




//  assignment: the number of elements must be the same
//              the fields must be convertible

#include <utility>
#include <iostream>
#include <tuple>
using std::tr1::tuple; using std::tr1::get;
using std::cout; using std::make_pair;

void show(int i, int j, const tuple<int,int&,int>& t)
{
  cout << i << ' ' << j << ": "
       << get<0>(t) << ' '
       << get<1>(t) << ' '
       << get<2>(t) << '\n';
}

void show(const tuple<int,int>& t)
{
  cout << get<0>(t) << ' '
       << get<1>(t) << '\n';
}

int main()
{
  int i = 1, j = 2;
  tuple<int,int&,int> t0(i, j, 3);
  tuple<int,double,char> t1(4, 5.1, '\6');
  show(i, j, t0);               // 1 2: 1 2 3
  t0 = t1;
  show(i, j, t0);               // 1 5: 4 5 6
  tuple<int,int> t2(1, 2);
  show(t2);                     // 1 2
  t2 = make_pair(3, 4);
  show(t2);                     // 3 4
  return 0;
}


//  get access a field   [ 0 .. N-1 ]


#include <tuple>
#include <iostream>
using std::tr1::tuple; using std::tr1::get;
using std::cout;

int main()
{
  tuple<int,int> t0(1, 2);
  cout << get<0>(t0) << ' ' << get<1>(t0) << '\n';   // 1 2
  return 0;
}



//  returning a reference, can be used to modified field:


#include <tuple>
#include <iostream>
using std::tr1::tuple; using std::tr1::get;
using std::cout;

void show(int i, int j, const tuple<int,int&,int> t)
{
  cout << i << ' ' << j << ": "
       << get<0>(t) << ' '
       << get<1>(t) << ' '
       << get<2>(t) << '\n';
}

int main()
{
  int i = 1, j = 2;
  tuple<int,int&,int> t0(i, j, 3);
  show(i, j, t0);               // 1 2: 1 2 3
  get<0>(t0) = 4;               // set first element to 4
  get<1>(t0) = 5.1;             // set object referred to by
                                // second element to 5
  get<2>(t0) = '\6';            // set third element to 6
  show(i, j, t0);               // 1 5: 4 5 6
  return 0;
}



//  access in compile time


#include <tuple>
#include <iostream>
using std::tr1::tuple; using std::tr1::tuple_size;
using std::cout;

typedef tuple<> tuple0;
typedef tuple<int> tuple1;
typedef tuple<int&,double&> tuple2;
typedef tuple<int,int,int,int,int> tuple5;

int main()
{
  cout << tuple_size<tuple0>::value << '\n';        // 0
  cout << tuple_size<tuple1>::value << '\n';        // 1
  cout << tuple_size<tuple2>::value << '\n';        // 2
  cout << tuple_size<tuple5>::value << '\n';        // 5
  return 0;
}



//  type_element is defined by typedef:


template <int Idx, class Tuple>
struct tuple_element
{
    typedef  ...  type;
};


#include <tuple>
#include <iostream>
#include <typeinfo>
using std::tr1::tuple; using std::tr1::tuple_element;
using std::cout;

typedef tuple<int> tuple1;
typedef tuple<int&,double&> tuple2;

template <class Ty>
void show_type()
{
  cout << typeid(Ty).name() << '\n';
};

int main()
{
  show_type<tuple_element<0, tuple1>::type>();  // int
  show_type<tuple_element<0, tuple2>::type>();  // int
  show_type<tuple_element<1, tuple2>::type>();  // double
  return 0;
}


//  Comparison

//  Two tuple object can be compared if they have 
//  the same number of elements.
//  == != < <= > >=
//  lexicographical + shortcut

//  for == and !=   member == is used
//  for < <= > >=   member <  is used


tuple<int, double, int> first(0,2.0,1);
tuple<long,float,int>   second(0,1.0,2);

             first < second

(1) get<0>(first)  < get<0>(second)     false
(2) get<0>(second) < get<0>(first)      false
(3) get<1>(first)  < get<1>(second)     false
(4) get<1>(second) < get<1>(first)      true

             first < second             false


#include <iostream>
#include <iomanip>
#include <tuple>
using std::tr1::tuple;
using std::cout; using std::boolalpha;

class C {
public:
  C(int i) : val(i) {}
  int value() const {return val;}
private:
  int val;
};

bool operator==(const C& left, const C& right)
{
  bool res = left.value() == right.value();
  cout << "  " << left.value()
       << " == " << right.value();
  cout << " is " << res << '\n';
  return res;
}

bool operator<(const C& left, const C& right)
{
  bool res = left.value() < right.value();
  cout << "  " << left.value()
       << " < " << right.value();
  cout << " is " << res << '\n';
  return res;
}

#define TEST(expr)          \
  cout << #expr << '\n';    \
  cout << "    result is " << (expr) << '\n'

typedef tuple<C&,C&,C&> tuple1;

int main()
{
  C a = 1;
  C b = 2;
  C c = 3;
  C d = 1;
  C e = 4;
  C f = 3;
  cout << boolalpha;            // set alphabetic form for bool
  tuple1 t0(a, b, c);
  tuple1 t1(d, e, f);
  TEST(t0 == t1);               // a == d is true, b == e is false,
                                // result is false
  TEST(t0 != t1);               // t0 == t1 is false, result is true
  TEST(t0 < t1);                // a < d is false,
                                // d < a is false and b < e is true,
                                // result is true
  TEST(t1 <= t0);               // t0 < t1 is true, result is false
  TEST(t1 > t0);                // t0 < t1 is true, result is true
  TEST(t0 >= t1);               // t0 < t1 is true, result is false
  return 0;
}


//  same extension to pair<T1,T2>