@hustbaer
Die Sache mit den traits gefällt mir, das nehme ich mal in die to-do Liste auf. Eigentlich braucht man auch nur die resize() Funktionalität. size und empty hängen direkt von Rows_ und Cols_ ab, begin lässt sich über std::begin realisieren. Auf der anderen Seite ist die Bündelung der Funktionalität in einer traits-Klasse besser handhabbar, weil alles an einer Stelle gemacht werden kann.
@Titan99
wenn die Spalten unterschiedliche Datentypen haben könnten
Wenn die Elemente alle unterschiedlich sein sollen nimmste halt den entsprechenden Datentyp (variant, any, etc.). Oder baust dir deinen eigenen mit deinen Anforderungen.
wenn die Spalten Namen als std::string haben könnten
Strings für Spalten- oder Zeilennamen braucht man je nach Anwendungsfall, die immer mitzuschleppen halte ich für keine gute Idee.
wenn das Array2D eine Ausgabe als std::ostream (?) als csv-Dateiformat haben könnte
Finde ich auch nicht gut. Du brauchst jetzt gerade die Daten im CSV Format, aber was ist bei jemandem, der die kompakt im Binärformat schreiben möchte? Oder ein anderes Trennzeichen als das Semikolon? Oder die Zellen in einzelne oder doppelte Hochkommata einfassen möchte, weil die Zelle ein Trennzeichen als Dateninhalt enthält?
Wenn du eine Klasse Datatable brauchst kannst du die doch einfach über Komposition realisieren. Dann bauste noch deine Spaltenüberschriften und Stream I/O dazu und fertig ist die Laube. Das geht mit weniger als 100 Zeilen Code.