Template mit später deklarierter Klasse



  • Das war keine Off-Topic Kritik, sondern ein Lösungsvorschlag, nämlich die Implementierung nicht über Vererbung sondern über Komposition zu benutzen. Dann kannst du deine Data Klasse auch in der Elementklasse definieren.
    Ansonsten bleibt dir nur -wie schon gesagt wurde- die Möglichkeit, die Data Klasse irgendwie vorher zu definieren.

    Nur interessehalber, wie groß ist so ein Stapel in 150MB denn etwa?



  • Xin schrieb:

    Die Frage ist, wie lässt sich meine Anforderung in C++ formulieren?

    Die Antwort ist wie gehabt: So garnicht.

    pumuckl schrieb:

    Du wirst dabei nicht drumrumkommen, die Element::Data als eigene Klasse zu implementieren und nicht als interne Klasse von Element.

    Das Problem bei dir ist nicht erst das Template, sondern schon die (Forward-)Deklaration von Element::Base - deshalb taucht die Fehlermeldung des Compilers auch dort schon auf. Du kannst dich nicht auf Interna einer Klasse beziehen (d.h. auch nicht sie deklarieren), bevor du die Definition der Klasse begonnen hast.

    Wieweit ähneln sich die N Element-Klassen? Eventuell reicht es da, ein einzelnes Element-Klassentemplate zu definieren, wenn es nur um unterschiedliche Data-Klassen geht. Ggf. kann man kleinere Unterschiede im Verhalten auch durch Policies ausdrücken.



  • brotbernd schrieb:

    Das war keine Off-Topic Kritik, sondern ein Lösungsvorschlag, nämlich die Implementierung nicht über Vererbung sondern über Komposition zu benutzen. Dann kannst du deine Data Klasse auch in der Elementklasse definieren.
    Ansonsten bleibt dir nur -wie schon gesagt wurde- die Möglichkeit, die Data Klasse irgendwie vorher zu definieren.

    Komposition hilft nicht, da die austauschbaren Teile über ein gemeinsames Interface (das auch über Implementation verfügt) auch durch das Projekt auf Wanderschaft gehen. Das Interface und die identische Implementation soll daher vererbt werden.

    Ich will Code reduzieren, nicht vermehren.

    brotbernd schrieb:

    Nur interessehalber, wie groß ist so ein Stapel in 150MB denn etwa?

    150MB würde ich sagen... zumindest verstehe ich die Frage in etwa so, als ob Du fragst, wie hoch ein 50m hoher Turm in etwa ist.

    Stell dir einfach einen Block 20 Jahre lang gereifter Software vor.

    pumuckl schrieb:

    Das Problem bei dir ist nicht erst das Template, sondern schon die (Forward-)Deklaration von Element::Base - deshalb taucht die Fehlermeldung des Compilers auch dort schon auf. Du kannst dich nicht auf Interna einer Klasse beziehen (d.h. auch nicht sie deklarieren), bevor du die Definition der Klasse begonnen hast.

    Ich weiß... daher die Frage, wie ich diese Interna vordeklarieren kann. Ich weiß, dass Element eine Subklasse Data besitzt - der Compiler weiß es noch nicht. Wie kann ich ihm versichern, dass die Erklärung noch kommen wird?

    Ich brauche im Template ausschließlich Referenzen bzw. Pointer - von denen ist die Größe bekannt. Es geht "nur" um Typsicherheit.

    pumuckl schrieb:

    Wieweit ähneln sich die N Element-Klassen? Eventuell reicht es da, ein einzelnes Element-Klassentemplate zu definieren, wenn es nur um unterschiedliche Data-Klassen geht. Ggf. kann man kleinere Unterschiede im Verhalten auch durch Policies ausdrücken.

    Die Element-Klassen implementieren ein gemeinsames Interface. Sogesehen sind sich sehr ähnlich. Die eigentliche Implementation hingegen ist sehr unterschiedlich, entsprechend auch die Daten, die verwendet werden.

    Aber wie ich schon sagte - das Problem ist nicht, das Ganze lauffähig zu formulieren, sondern die einzelnen Data-Klassen in der jeweiligen Elementklasse zu verstecken.
    Ich suche das Gedicht, das rhetorisch Schöne. Das Zeug in Prosa darzubieten ist nicht mein Problem.



  • Xin schrieb:

    Stell dir einfach einen Block 20 Jahre lang gereifter Software vor.

    Sorry für OT:
    "20 Jahre gereift" klingt nach Wein. Den man 20 Jahre lang liegen gelassen hat.
    Mit der Analogie stelle ich mir die 20 Jahre gereifte Software lieber nicht vor - C++ von vor 20 Jahren ist ja nicht gerade das Höchste der Gefühle 😉



  • pumuckl schrieb:

    Xin schrieb:

    Stell dir einfach einen Block 20 Jahre lang gereifter Software vor.

    Sorry für OT:
    "20 Jahre gereift" klingt nach Wein. Den man 20 Jahre lang liegen gelassen hat.
    Mit der Analogie stelle ich mir die 20 Jahre gereifte Software lieber nicht vor - C++ von vor 20 Jahren ist ja nicht gerade das Höchste der Gefühle 😉

    Wäre das von vor 20 Jahren nur C++ gewesen....

    Lass Dir noch den Block auf der Zunge zergehen und fühle die leicht modrige Note von Fortran 77 im Abgang, während Dir ein wenig Visual Basic 6 im Halse kratzt und dafür sorgt, dass Dir ein Klumpen aus C# und Python in ebendiesem stecken bleibt.

    Das Design einer Software ist nach 20 Jahren ausgereift. Oder darüber hinaus. 😉
    Aber das heißt ja nicht, dass man es nicht aufbessern könnte.

    Der Begriff "Software-Archäologe" existiert tatsächlich - wusste ich vorher auch nicht. ^^

    </offtopic>



  • Xin schrieb:

    Lass Dir noch den Block auf der Zunge zergehen und fühle die leicht modrige Note von Fortran 77 im Abgang, während Dir ein wenig Visual Basic 6 im Halse kratzt und dafür sorgt, dass Dir ein Klumpen aus C# und Python in ebendiesem stecken bleibt.

    😋

    Das Design einer Software ist nach 20 Jahren ausgereift. Oder darüber hinaus. 😉

    Sagt die alte Schule 😉 Aktuell liest man häufiger die Meinung, dass das tatsächliche Design direkt im Code steckt und vom beabsichtigten Design mehr oder weniger abweicht (In der Theorie weniger, in der Praxis mehr). Wenn sich also der Code ändert, ändert sich das Design. Und das muss somit genau wie der Code gewartet und gepflegt werden. Nach der Meinung hat sich das was mit ausgereift 😉

    Aber bevor jetzt die nächste Glaubensdiskussion vom Gartenzaun bricht back to Topic: Wenn du uns noch ein wenig drumherum zu deinem beabsichtigten Code/Design gibst, finden wir vielleicht zusammen einen Weg, das in C++ schön (elegant, wartbar, ohne Code-Duplizierung,...) umzusetzen 🙂



  • pumuckl schrieb:

    Das Design einer Software ist nach 20 Jahren ausgereift. Oder darüber hinaus. 😉

    Sagt die alte Schule 😉

    Hier spricht man von "hysterisch gewachsenen Strukturen". 😉

    Aber es funktioniert.

    pumuckl schrieb:

    Aktuell liest man häufiger die Meinung, dass das tatsächliche Design direkt im Code steckt und vom beabsichtigten Design mehr oder weniger abweicht (In der Theorie weniger, in der Praxis mehr). Wenn sich also der Code ändert, ändert sich das Design. Und das muss somit genau wie der Code gewartet und gepflegt werden. Nach der Meinung hat sich das was mit ausgereift 😉

    Ich verwerfe ein Design, wenn ich sehe, dass es von meiner Absicht abweicht. Der Nachteil ist, dass Code so viel Pflege bedarf, aber ich bei meinen privaten Projekten Erweiterungen meist einfach dazustellen kann und die Sache läuft.

    pumuckl schrieb:

    Aber bevor jetzt die nächste Glaubensdiskussion vom Gartenzaun bricht back to Topic: Wenn du uns noch ein wenig drumherum zu deinem beabsichtigten Code/Design gibst, finden wir vielleicht zusammen einen Weg, das in C++ schön (elegant, wartbar, ohne Code-Duplizierung,...) umzusetzen 🙂

    Wie gesagt - das ist komplette System aufzuführen ist recht aufwändig und das eigentliche Problem - scheint mir in C++ so nicht formulierbar zu sein. Ich hatte noch ein paar weitere Ideen, die der VC++ auch nicht geschluckt hat, ich probiere das heute abend nochmal mit dem GCC zu Hause aus. VC++ ist was Templates angeht sowieso etwas schwachbrüstig.

    Da mich das hier aber nicht weiterbringt habe ich begonnen das Design zu ändern - damit erübrigt sich die Frage - für dieses Projekt jedenfalls.



  • Xin schrieb:

    Komposition hilft nicht, da die austauschbaren Teile über ein gemeinsames Interface (das auch über Implementation verfügt) auch durch das Projekt auf Wanderschaft gehen. Das Interface und die identische Implementation soll daher vererbt werden.

    Ich hab es zwar schon im ersten Post gesagt, will es aber nochmal erwähnen, weil es sich bei den Informationen und Aussagen die wir hier haben ein wenig so anhört als hättest du vielleicht eine falsche Vorstellung (vielleicht ist es auch nicht so).
    Da alle Elementklassen von einer anderen Basisklasse erben, nämlich Interface<MeinInterfaceUnterscheidetSichHierVonAllenAnderen> haben sie eben keine gemeinsame Schnittstelle. Sie haben alle eine Schnittstelle die einfach nur "zufällig" den gleichen Namen und gleiche Signatur hat. Dazu braucht man aber keine öffentliche Vererbung. Alles was du bekommst ist die Implementierung von bool func(DataInterface & bla) (macht die noch mehr als geprüfte Konvertierung zu DataType). Und für die Wiederverwendung einer Implementierung brauchst du keine Vererbung, mit der du hier ja ein offensichtliches Problem hast.

    Ach und die Frage nach dem Stapel war natürlich die Frage nach der Anzahl der Elementklassen (in Stück) 😉



  • brotbernd schrieb:

    Ich hab es zwar schon im ersten Post gesagt, will es aber nochmal erwähnen, weil es sich bei den Informationen und Aussagen die wir hier haben ein wenig so anhört als hättest du vielleicht eine falsche Vorstellung (vielleicht ist es auch nicht so).

    Es spricht grundsätzlich nichts dagegen, es in seine Überlegungen einzubeziehen, dass das Gegenüber falsche Vorstellungen der Programmierung hat. Ich programmiere jetzt seit 16 Jahren C++ und seit über 24 Jahren programmiere ich in anderen Sprachen. Ich mache das beruflich, habe bereits Schulungen für C++ gegeben und ich versichere Dir nochmals, dass ich hier ein syntaktisches Problem habe, das offenbar nicht lösbar ist und dass ich in der Lage bin eine Ableitung zu formulieren.

    Wenn ich in diesem Forum Anfragen stelle, so sind diese trivial und ich finde einfach den Schalter nicht oder sie sind nicht trivial, weil die Probleme nicht lösbar sind, bzw. ich beantworte sie dann oftmals selbst, weil sie nicht trivial sind.
    Ich muss aber sagen, dass bei nicht trivialen Sachen - unabhängig davon ob ich die Frage stelle oder eine Antwort gebe - in diesem Forum sich immer mindestens einer findet, der alles, was er für ungewöhnlich hält mit 'falsch' gleichsetzt und mir erklärt, dass ich nicht verstehe, was ich tue alternativ dass was ich tue sinnlos ist und dann auch interessanterweise nahezu grundsätzlich von "wir" sprechen. Diesbezüglich hatte ich schon sehr lange, sinnfreie Diskussionen hier und ich plane das nicht zu wiederholen.

    Das ist der Grund, warum ich in diesem Forum nur noch wenige Fragen stelle und in meinem Forum darauf achte, dass Formulierungen wie "wir hier haben ein wenig so anhört als hättest du vielleicht eine falsche Vorstellung (vielleicht ist es auch nicht so)" nicht aufkommen.

    Ich fragte nach einer möglichen Syntax, nicht nach einer Beratung für eine Designentscheidung. Dafür habe ich - absichtlich - zuwenig Details gegeben, als dass eine seriöse Beratung möglich wäre, um genau das zu vermeiden.

    brotbernd schrieb:

    Da alle Elementklassen von einer anderen Basisklasse erben, nämlich Interface<MeinInterfaceUnterscheidetSichHierVonAllenAnderen> haben sie eben keine gemeinsame Schnittstelle. Sie haben alle eine Schnittstelle die einfach nur "zufällig" den gleichen Namen und gleiche Signatur hat. Dazu braucht man aber keine öffentliche Vererbung.

    Sie haben eine gemeinsame Schnittstelle über die Basisklasse der Data-Varianten. Diese Methode versucht per dynamic_cast auf "DataType" zu casten und leitet das im Erfolgsfall an das jeweilige Element weiter. Die unterschiedlichen Elemente können so typsicher gleich mit ihrer erforderlichen Datenklasse arbeiten, ohne diese selbst noch downcasten zu müssen.

    brotbernd schrieb:

    Und für die Wiederverwendung einer Implementierung brauchst du keine Vererbung, mit der du hier ja ein offensichtliches Problem hast.

    Nein, ich habe ein deklaratives Problem, ich habe einen Typ, den C++ innerhalb eines Templates nicht kennen möchte. Die Vererbung funktioniert wunderbar.
    Was ich brauche oder nicht und womit ich offensichtlich Probleme habe, schrieb ich aber bereits im Eingangsposting.

    brotbernd schrieb:

    Ach und die Frage nach dem Stapel war natürlich die Frage nach der Anzahl der Elementklassen (in Stück) 😉

    Stetig wachsend.

    Deswegen soll die Implementierung ja auch so einheitlich wie möglich sein.



  • Der Thread war mir zwar eigentlich eindeutig zu pampig, aber mir ist gerade noch was eingefallen, wo mir das Wort mixin nochmal über den Weg lief. Vielleicht kannst du ja damit was anfangen:

    class StandardData
    {
    public:
        virtual ~StandardData(){}
        int a;
    };
    
    template<typename ElementT>
    class Interface
    {
    public:
        bool func(StandardData & bla)
        {
            typedef typename ElementT::Data* DataPtr;
            DataPtr d = dynamic_cast<DataPtr>(&bla);
            if (!d)
                return false;
            ElementT* el = static_cast<ElementT*>(this);
            el->funcImpl(*d);
            return true;
        }
    };
    
    class Element : public Interface<Element>
    {
    public:
       class Data : public StandardData
       {
         int b;
       };
    
       bool funcImpl(Data & myData)
       {
           std::cout << "Element func\n";
       }
    };
    
    class Element2 : public Interface<Element2>
    {
    public:
       class Data : public StandardData
       {
         int b;
       };
    
       bool funcImpl(Data & myData)
       {
           std::cout << "Element2 func\n";
       }
    };
    
    template<typename E, typename D>
    bool foo(E& e, D& d)
    {
        return e.func(d);
    }
    
    int main()
    {
        Element e;
        Element::Data d;
        Element2::Data d2;
        if (!foo(e, d))
            std::cout << "Da ist was schiefgegangen.";
        if (!foo(e, d2))
            std::cout << "Da ist was schiefgegangen.";
        return 0;
    }
    

    Ein Kommentar dazu gebe ich natürlich nicht ab, das ist hier ja unerwünscht 😉


Anmelden zum Antworten