Class1 cannot access private member declared in Class1
-
ok - ich habs jz doch endlich mal geschafft:
template <size_t Tct> class TPoint { template <size_t lhs_count, size_t rhs_count> friend TPoint <lhs_count> Point (const TPoint <rhs_count> &rhs); public: static const size_t dimension = Tct; private: float value[dimension]; template <size_t Tct_rhs> void copy (const float *first) { if(dimension <= Tct_rhs) { std::copy (first, first+dimension, value); } else //Tct_rhs < dim { std::copy (first, first+Tct_rhs, value); for(float *i(value+Tct_rhs+1), *e(value+dimension); i != e; ++i) { *i = 0; } } } public: float& operator[] (size_t i) { assert (i < dimension); return value[i]; } const float& operator[] (size_t i) const { assert (i < dimension); return value[i]; } TPoint() { for (float *iter(value), *end(value+dimension); iter != end; ++iter) { *iter = 0; } } template <size_t Tct_rhs> TPoint(float _value[Tct_rhs]) { copy (_value); } TPoint (const TPoint &rhs) { copy <rhs.dimension> (rhs.value); } TPoint& operator = (const TPoint &rhs) { copy <rhs.dimension> (rhs.value); return *this; } }; template <size_t lhs_count, size_t rhs_count> TPoint <lhs_count> Point (const TPoint <rhs_count> &rhs) { TPoint <lhs_count> lhs; lhs.copy <rhs_count> (rhs.value); return lhs; }Es gefällt mir zwar nun nicht gerade perfekt, aber es funktioniert ^^
bb
-
-
ahh ^^ danke
hmmm... nach friend hatte ich zwar gefragt aber hätte nicht gedacht, dass das notwendig sei...Ich denke aber trotzdem nicht, dass das geht, was ich am Anfang versucht hatte - ist vielleicht auch gar nicht so gut, wenn der User explizit sagen muss, dass sich die Anzahl der Dimensionen ändern soll...
bb
-
Das ist denke ich einer der Standard-Denkfehler wenns um Templateklassen geht: zwei verschiedene Instantiierungen eines Klassentemplates sind auch zwei verschiedene Klassen und können nicht auf die privates der anderen Instantiierungen zugreifen. Auch wenn der Name des Templates der selbe ist.
Dennoch könnte in deinem Fall der Pseudo-Copy-Ctor ohne friends funktionieren:
class DaddyPoint { proteted: virtual void copy(std::size_t n, float* target) = 0; }; template <size_t Tct> class TPoint : public DaddyPoint { public: static const size_t dimension = Tct; private: float value[dimension]; public: template <size_t Tct2> explicit TPoint(TPoint<Tct2> const& other) { DaddyPoint const& othersDaddy = other; othersDaddy.copy(dimension, value); } private: virtual void copy(size_t n, float* target) { std::copy(value, vlaue + std::min(n, dimension), target); if (dimension < n) { std::fill(target+dimension, target+n, 0.0f); } } };Der Trick ist, dass man dem "fremden" Punkt den Zugriff gewährt und sagt "mach mal bitte", statt selber auf dessen innereien zuzugreifen. Das explicit beim Pseudo-Copy (Pseudo, weils ja von ner anderen Dimension ist) halte ich für notwendig, sonst würde folgendes ohne weitere Warnungen compilieren:
TPoint<1> p1; TPoint<2> p2; TPoint<3> p3; p2 = p1 + p3; //vorausgesetzt es gibt den op+ als Member von TPointdie letzte Zeile ist etwas tricky: Wenn TPoint einen op+(TPoint) als Member hat, dann wird p3 stillschweigend umgewandelt in einen TPoint<1>, daraufhin wird das Ganze beim op= implizit in einen TPoint<2> gewandelt. Um sowas zu vermeiden ist explicit ja da

Ich hab extra auf op+ als Member angesprochen, denn wenns einen freien Operator+ mit zwei gleichen TPoint-argumenten gibt (natürlich ein template), dann kann der Compiler nicht entscheiden welchen der Parameter er an den anderen anpassen soll.
-
hmm... Danke - ich habe es jetzt über eine extra Funktion geregelt und finde das im Nachhinein auch schöner (eben weil die Umwandlungen nicht "von Geisterhand" passieren können ^^)
Falls es jemanden interessiert:
template <size_t Tct> class TPoint { template <size_t lhs_count, size_t rhs_count> friend TPoint <lhs_count> Point (const TPoint <rhs_count> &rhs); public: static const size_t dimension = Tct; private: float value[dimension]; template <size_t Tct_rhs> void copy (const float *first) { if(dimension <= Tct_rhs) { std::copy (first, first+dimension, value); } else //Tct_rhs < dim { std::copy (first, first+Tct_rhs, value); for(float *i(value+Tct_rhs+1), *e(value+dimension); i != e; ++i) { *i = 0; } } } public: float& operator[] (size_t i) { assert (i < dimension); return value[i]; } const float& operator[] (size_t i) const { assert (i < dimension); return value[i]; } TPoint() { for (float *iter(value), *end(value+dimension); iter != end; ++iter) { *iter = 0; } } template <size_t Tct_rhs> TPoint(float _value[Tct_rhs]) { copy (_value); } TPoint (const TPoint &rhs) { copy <rhs.dimension> (rhs.value); } TPoint& operator = (const TPoint &rhs) { copy <rhs.dimension> (rhs.value); return *this; } TPoint& operator += (const TPoint &rhs) { const float *from (rhs.value); for (float *iter (value), *end (value+dimension); iter != end; ++iter, ++from) { *iter += *from; } return *this; } TPoint operator - () const { TPoint tmp(*this); for (float *iter(tmp.value), *end(tmp.value+dimension); iter != end; ++iter) { *iter = -*iter; } return tmp; } TPoint& operator -= (const TPoint &rhs) { return *this += -rhs; } }; template <size_t lhs_count, size_t rhs_count> TPoint <lhs_count> Point (const TPoint <rhs_count> &rhs) { TPoint <lhs_count> lhs; lhs.copy <rhs_count> (rhs.value); return lhs; } template <size_t ct> std::istream& operator >> (std::istream &s, TPoint<ct> &point) { for (size_t i (0); i != ct; ++i) { s >> point[i]; } return s; } template <size_t ct> std::ostream& operator << (std::ostream &s, const TPoint<ct> &point) { s << point[0]; for (size_t i(1), e(ct); i < e; ++i) { s << ";" << point[i]; } return s; } template <size_t dim1, size_t dim2> TPoint<dim1> operator + (const TPoint<dim1>& lhs, const TPoint<dim2>& rhs) { TPoint<dim1> tmp = Point <dim1, dim2> (lhs); return tmp += rhs; } template <size_t dim1, size_t dim2> TPoint<dim1> operator - (const TPoint<dim1>& lhs, const TPoint<dim2>& rhs) { return lhs + -rhs; }Falls jemand eine Meinung dazu hat, würde ich diese natürlich auch gern (hier) lesen ^^
Die op += und -= sind mit Absicht nicht für andere (also verschiedene) Dimensionen implementiert...
Mir schon klar, dass da noch ne ganze Menge fehlt (Abstandsberechnung, Skalarmultiplikation, ...) - aber denke, dass sie so doch schon rel. viel kann, was man von einer Klasse für Punkte erwarten könnte ^^bb
-
Tip: du kannst das was du mit deinem ursprünglichen "swap" Template (später "copy") wolltest schon machen, nur ist die Syntax anders als du es probiert hast:
template <size_t Tct_rhs> void copy (const float (&first)[Tct_rhs]) // sieht komisch aus, geht aber { // ... }Du kannst copy dann auch ohne expliziter Angabe der Grösse aufrufen, und der Compiler checkt ob die Grösse auch stimmt:
void test() { float foo[42]; copy(foo); // ruft copy<42>(foo) auf copy<99>(foo); // Fehler }
-
Jopp, das ich das kann, weiß ich - nur dummerweise konnte der MSVC 2008 die Templates nicht von allein auflösen - also mustse ich ihm ein wenig Hilfe geben - indem ich ihm die Anzhl gegeben hab - und dann dachte ich mir, dass ich ihm dann auch gleich nur nen Pointer übergeben kann - aber ok, dann kann ichs auch mit der Referenz machen, wie du sie mir geschickt hast - danke : >
bb
-
nur dummerweise konnte der MSVC 2008 die Templates nicht von allein auflösen - also mustse ich ihm ein wenig Hilfe geben - indem ich ihm die Anzhl gegeben hab
MSVC 2008 kann das sehr schön auflösen. Klappt eigentlich seit MSVC 2003. Bei VC 6 bin ich mir nicht sicher, kann leicht sein dass der das noch nicht checkt.
Das Problem ist dass in deinem Beispiel die Referenz fehlt, deswegen geht es nicht. Die Syntax die du verwendet hast ist nur die Umständliche Version ein Parameter des Typs T* zu schreiben. Soll heissen:
void foo(T param[10]); // ist genau dasselbe wie void foo(T param[]); // und auch genau dasselbe wie void foo(T* param);Lässt sich auch schön zeigen durch ein kleines Testprogramm:
#include <iostream> void foo1(int param[10]) {} void foo2(int param[20]) {} void foo3(int param[]) {} void foo4(int* param) {} template <class T> struct test { static int bar; static char const* get_name() { return typeid(T).name(); } }; template <class T> int test<T>::bar = 0; template <class T> void test2(T) { std::cout << "type: " << test<T>::get_name() << "\n"; test<T>::bar++; std::cout << "bar = " << test<T>::bar << "\n"; } int main() { test2(&foo1); test2(&foo2); test2(&foo3); test2(&foo4); int i = 0; foo1(&i); // foo1 ist "void foo1(int param[10])" - trotzdem gibt das keinen fehler, // weil die 10 in "[10]" vollkommen "ignoriert" wird, und "param" // hier eben letztlich nur ein einfacher Zeiger ist return 0; }Die "[]" Schreibweise für Zeiger-Parameter ist IMO sehr verwirrend - viele Leute erwarten sich etwas ganz anderes wenn sie das schreiben, bzw. auch wenn sie es lesen. Deswegn ist das auch etwas was ich nie nie niemals verwende.
-
Hmm.. interessantes Beispiel - gut - beim copy-Aufruf gibt es wirklich keinen Fehler mehr, wenn ich das Template-Argument net explizit mit angebe - wobei ich schwören könnte, dass es noch gestern nicht ging - naja, hab ich mich mal wieder geirrt ^^
Aber bei Point <x, y> brauch ich sie auf jeden Fall - wobei man das ja wiederrum auch durchaus positiv untermauern könnte - aber ein wenig nerven tuts ja schon ^^
TPoint <3> a; a[0] = 1; a[1] = 2; a[2] = 3; TPoint <2> b = Point <2, 3> (a); TPoint <2> B (b); TPoint <3> A(Point <3, 2> (B));template <size_t lhs_count, size_t rhs_count> TPoint <lhs_count> Point (const TPoint <rhs_count> &rhs) { TPoint <lhs_count> lhs; lhs.copy (rhs.value); return lhs; }bzw.
template <size_t Tct> class TPoint { template <size_t Tct_rhs> void copy ( const float (&first)[Tct_rhs] ) { if(dimension <= Tct_rhs) { std::copy (first, first+dimension, value); } else //Tct_rhs < dim { std::copy (first, first+Tct_rhs, value); std::fill (value+Tct_rhs+1, value+dimension, 0.f); } } };Danke ^^
-
Klar musst du bei "Point<x, y>" noch was angeben, da x ja nur im Return-Typ vorkommt - das kann der Compiler logischerweise nicht anhand der Parameter erraten.
Du musst aber "y" nicht mit angeben, also "Point<2>(a)" sollte in deinem Beispiel reichen.
