#include<iostream>
#include<string>
#include<vector>
using namespace std;

template<class T1, class T2>
class Paire {
public:
    Paire(T1 fst, T2 snd) : fst(fst), snd(snd) {}
    T1 fst;
    T2 snd;
};
template<class T1, class T2> // bien penser a remettre le template !
ostream &operator<<(ostream &out, const Paire<T1,T2> &p) {
    out << "(" << p.fst << ", " << p.snd << ")";
    return out;
}
template<class T>
ostream &operator<<(ostream &out, const vector<T> &v) {
    for (int i = 0; i < v.size(); i++) {
        out << v[i];
        if (i < v.size() -1) out << ", ";
    }
    return out;
}

class ExceptionTaille {};
template<class T1, class T2> 
vector<Paire<T1,T2> > // Attention > > et pas >> qui est un operateur !
    zip(const vector<T1> &v1, const vector<T2> &v2) throw(ExceptionTaille) {
    vector<Paire<T1,T2> > v;
    if (v1.size() != v2.size()) 
        throw ExceptionTaille();
    for (int i = 0; i < v1.size(); i++)
        v.push_back(Paire<T1,T2>(v1[i],v2[i]));
    return v; // attention ce n'est pas tres malin de renvoyer un vecteur
}

template<class T1, class T2>
Paire<T1,T2> implicit_pairing(T1 v1, T2 v2) {
    return Paire<T1,T2>(v1,v2);
}

int main() {
    Paire<int,string> p(3, "a");
    cout << p << endl;
    vector<int> v1; v1.push_back(3); v1.push_back(4);
    vector<string> v2; v2.push_back("a"); v2.push_back("b");
    cout << zip(v1,v2) << endl;
    cout << implicit_pairing(3, "a") << endl;
}
