#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;
}