O
hmm. ja, 100% glücklich bin ich in der Tat nicht, jetzt wo ich es mal implementiert habe.
Im Grunde ist meine Anforderung wie folgt:
Ich habe zwei Mengen von Objekten
std::vector<boost::shared_ptr<A> > myAs;
std::vector<boost::shared_ptr<B> > myBs;
und ich muss sie in irgendeiner weise als
std::vector<boost::shared_ptr<MyPair<A,B> > > myABPairs;
ausdrücken können. Diese Abhängigkeit muss in 2 Richtungen erfolgen. Ich muss sowohl aus myABPairs wieder myAs und myBs erzeugen können, als auch aus MyAs und myBs das myABPair. Wir haben gerade hier die eine Richtung gelöst. Die andere Richtung bleibt ein Mysterium :).
Die nächste Anforderung ist, dass ich irgendwie die Existenz der shared_ptr verstecken will, da die Implementation der shared-ownership ein Implementationsdetail ist, das wir eventuell auch noch einmal ändern wollen.
Von außen sieht der User am Ende nur:
Container<A> myAs;
Container<B> myBs;
//MyPair ist von mir als Entwickler frei wählbar :)
Container<MyPair<A,B> > myABPairs = zip(myAs,myBs);
Container<A> myAs2 = splitFirst(myABPairs);
Container<B> myBs2 = splitSecond(myABPairs);
Ich hatte eine Lösung implementiert, wobei
Container<MyPair<T1,T2> > spezialisiert war und intern einfach nur Container<A> und Container<B> speicherte. Es wurden dann bei jedem Elementzugriff Proxyobjekte für MyPair<A,B> erzeugt. Das war ein riesiger Aufwand (fast 1000 Zeilen template Alptraum) und führte schließlich zu dem Problem, dass das Resultat kein Container im Sinne des Standards ist(im Gegensatz zu Container<A> und Container<B>). Wenn ich das Umgehe, indem ich einfach ein anderes Objekt benutze (MyPairContainer<A,B>) habe ich aber noch viel viel mehr Code-Duplikation, weil eine Menge Anwendungscode auf Container<T> templatisiert ist.
Eine Lösung die mir momentan vorschwebt ist: ich schreibe MyPair um, so dass es folgendes interface hat:
template<class A, class B>
struct MyPair{
private:
shared_ptr<A> aRef;
shared_ptr<B> bRef;
public:
A& first(){
return *aRef;
}
B& second(){
return *aRef;
}
};
und dann spezialisiere ich meinen Container darauf. Wenn ich das geschickt anstelle, kann ich 80-90% in irgendeine Basis oder abgeleitete Klasse auslagern und muss nicht ewig viel duplizieren. Naja und halt jede Anwendung von first durch first() ersetzen.
Bessere Vorschläge? Das ist sogar für meine Verhältnisse ein ziemlicher Hack.