Mixins und Funktionsschablonen sind zwei verschiedene Möglichkeiten, einem breiten Satz von Typen ein Verhalten zu verleihen, sofern diese Typen bestimmte Anforderungen erfüllen.
Nehmen wir zum Beispiel an, dass ich einen Code schreiben möchte, der es mir erlaubt, ein Objekt in einer Datei zu speichern, solange dieses Objekt eine toString
Mitgliedsfunktion (dies ist ein eher dummes Beispiel, aber seien Sie nachsichtig mit mir). Eine erste Lösung besteht darin, eine Funktionsvorlage wie die folgende zu schreiben:
template <typename T>
void toFile(T const & obj, std::string const & filename)
{
std::ofstream file(filename);
file << obj.toString() << '\n';
}
...
SomeClass o1;
toFile(o1, "foo.txt");
SomeOtherType o2;
toFile(o2, "bar.txt");
Eine andere Lösung ist die Verwendung eines Mixin, das CRTP :
template <typename Derived>
struct ToFile
{
void toFile(std::string const & filename) const
{
Derived * that = static_cast<Derived const *>(this);
std::ofstream file(filename);
file << that->toString() << '\n';
}
};
struct SomeClass : public ToFile<SomeClass>
{
void toString() const {...}
};
...
SomeClass o1;
o.toFile("foo.txt");
SomeOtherType o2;
o2.toFile("bar.txt");
Was sind die Vor- und Nachteile dieser beiden Ansätze? Gibt es einen bevorzugten Ansatz und wenn ja, warum?