Funktion abhängig der Größe eines Templateparameters überladen



  • @Ethon: Dir ist hoffentlich klar, daß die Größe eines Objekts nicht der einzige Grund ist, zwischen der Übergabe als Referenz und der Übergabe als Kopie zu wählen. Es gibt genug Klassen, die (aus Sicht des sizeof()) klein sind, aber trotzdem nicht als Kopie übergeben werden können oder sollten sollten, z.B.:
    - nicht-kopierbare Objekte (z.B. boost::scoped_ptr - da verhindert das Klassendesign, daß sie kopiert werden)
    - Container (enthalten mitunter nur ein bis zwei Zeiger im "Rumpf", aber der Kopierkonstruktor muß möglicherweise größere Datenmengen auf dem Heap kopieren)
    - Klassen mit destruktiver Kopiersemantik (z.B. std::auto_ptr)

    Da würde ich im Zweifelsfall lieber ein paar Prozessortakte für die Dereferenzierung in Kauf nehmen als mir mit derartigen Problemen meine Programme zu zerstören.



  • CStoll schrieb:

    Da würde ich im Zweifelsfall lieber ein paar Prozessortakte für die Dereferenzierung in Kauf nehmen als mir mit derartigen Problemen meine Programme zu zerstören.

    Also geht's nicht sinnvoll, die paar Takte zu sparen zu automatosieren. Schade. C++ ist dahingehend eine schlechte Spache. 😞



  • Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat? Wenn ja, könnte man die obengenannten enable_if-Konstrukionen darauf ansetzen.



  • CStoll schrieb:

    Es gibt genug Klassen, die (aus Sicht des sizeof()) klein sind, aber trotzdem nicht als Kopie übergeben werden können oder sollten sollten

    Gute Einwände, CStoll.

    Wenn man etwas defensiver vorgeht, kann man diese Probleme vermeiden. Beschränkt man sich auf skalare Typen, sind die meisten Fälle sind dann trotzdem noch abgedeckt. Mit der Metafunktion is_scalar aus Boost.TypeTraits (oder TR1/C++0x-Äquivalenten) kann diese Typeigenschaft geprüft werden. Das grösste Problem sehe ich hier bei Iteratoren, für diese müsste man allenfalls eine Spezialisierung einrichten. Vielleicht aber besser bei einem eigenen Template als direkt bei is_scalar .

    Ist halt immer die Frage, wie weit man mit der Optimierung gehen will...

    CStoll schrieb:

    Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat?

    Suchst du has_trivial_copy ? 🙂



  • Nexus schrieb:

    CStoll schrieb:

    Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat?

    Suchst du has_trivial_copy ? 🙂

    Ja, ich glaube das war's. (wobei ich die Doku so deute, daß das eher pessimistisch bei der Aussage ist - aber für praktische Zwecke dürfte das reichen)



  • CStoll schrieb:

    Kennst du einen Weg zu fragen, ob ein gegebener Typ einen trivialen Kopierkonstruktor hat? Wenn ja, könnte man die obengenannten enable_if-Konstrukionen darauf ansetzen.

    Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat. Ich denke, mit ihnen wäre einiges einfacher.
    Ups, wo wir schon dabei sind,
    - warum ist der Rückgabetyp eines Kunstuktors nicht void,
    - warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?



  • volkard schrieb:

    Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat.

    Ich kenne Smalltalk nicht, wie sehen die aus? Läuft das nicht auf was Ähnliches wie Template-Metaprogrammierung heraus, nur etwas benutzerfreundlicher?

    volkard schrieb:

    warum ist der Rückgabetyp eines Kunstuktors nicht void

    Wahrscheinlich weil der Konstruktor nicht nichts zurückgibt. Schliesslich wird ein Konstruktor in einer Deklaration oder in einem Ausdruck aufgerufen, der das eben konstruierte Objekt zurückgibt. Der Typ eines solchen Ausdrucks ist im Gegensatz zu void -Funktionen nicht void .

    volkard schrieb:

    - warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?

    Ich bin mir nicht sicher, könnte mir aber vorstellen, damit man sowas schreiben kann:

    boolExpr ? DoSomething() : throw Exception()
    


  • Quatsch



  • Nexus schrieb:

    volkard schrieb:

    Nein. Leider hat C++ keine Metaklassen wie Smalltalk sie hat.

    Ich kenne Smalltalk nicht, wie sehen die aus? Läuft das nicht auf was Ähnliches wie Template-Metaprogrammierung heraus, nur etwas benutzerfreundlicher?

    Nee. Ist die Magie über der Klasse als normale Klasse. Dadurch erst zugreifbar für Metaprogrammierung. In C++ ist es einfach nicht da.

    Nexus schrieb:

    volkard schrieb:

    warum ist der Rückgabetyp eines Kunstuktors nicht void

    Wahrscheinlich weil der Konstruktor nicht nichts zurückgibt.

    Also falsch.

    Nexus schrieb:

    volkard schrieb:

    - warum ist der Rückgabetyp eines throw-Ausdrucks void, also warum ist es ein Ausdruck?

    Ich bin mir nicht sicher, könnte mir aber vorstellen, damit man sowas schreiben kann:

    boolExpr ? DoSomething() : throw Exception()
    

    Wozu? Nur um im assert werfen zu können? Der Fehler war doch, daß assert ein Ausdruck war. Keinen hat's gejuckt.



  • volkard schrieb:

    wo wir schon dabei sind,

    Wieso fordert main kein return ?
    EDIT: Oder wieso ist argc ein int un nicht ein unsigned ?



  • volkard schrieb:

    warum ist der Rückgabetyp eines Kunstuktors nicht void

    Im Prinzip ist es irrelevant, welchen Rückgabewert der Konstruktor hat, weil es keine Möglichkeit gibt, ihn direkt aufzurufen.
    MyClass a = MyClass(...) ruft ihn nur indirekt auf, sonst müsste es MyClass::MyClass(...) heißen. Der Konstruktor ist aber auch nicht statisch, also ginge das auch nicht. Somit müsste man also danach a.MyClass(...) aufrufen können, das geht nicht.
    Da der Konstruktor somit niemals in einem Ausdruck verwendet werden kann, braucht er keinen Rückgabewert.

    Interessanter wird die Sache beim Destruktor. Der kann in Ausdrücken verwendet werden. Laut http://ideone.com/gn36G scheint er beim GCC auch tatsächlich void als Rückgabewert zu haben, ob das der Standard genauso sieht, weiß ich aber nicht.



  • ipsec schrieb:

    volkard schrieb:

    warum ist der Rückgabetyp eines Kunstuktors nicht void

    Im Prinzip ist es irrelevant, welchen Rückgabewert der Konstruktor hat, weil es keine Möglichkeit gibt, ihn direkt aufzurufen.

    Schade. Wäre direkter, als der Umweg per placement new.

    ipsec schrieb:

    MyClass a = MyClass(...) ruft ihn nur indirekt auf, sonst müsste es MyClass::MyClass(...) heißen. Der Konstruktor ist aber auch nicht statisch, also ginge das auch nicht. Somit müsste man also danach a.MyClass(...) aufrufen können, das geht nicht.

    Eine Aufrufabkürzung darf es ja geben. Warum ist er nicht statisch?

    MyClass* p=malloc(sizeof(MyClass));
    MyClass::constructor(p);
    

    sieht doch hübsch aus. Man könnte zum Beispiel auf natürliche Weise die Adresse der Funktion ziehen.

    Da der Konstruktor somit niemals in einem Ausdruck verwendet werden kann, braucht er keinen Rückgabewert.

    void als Rückgabewert würde aber auch nicht schaden, sondern den Laden ein wenig vereinfachen. Third-Party-Tools hätten es leichter, den Konstruktor als Funktion zu erkennen. Und schau Dir folgenden seltsamen Code an:

    void test(){
        //tuwas
        //if(was)
            return throw 0;//Klappt, seit der so spät nachträglichen Sprachvereinfachung, daß man void returnen darf. 
        //tuwasanderes
    }
    
    class MyClass{
        MyClass(){
        //tuwas
        //if(was)
            return throw 0;//error: returning a value from a constructor
        //tuwasanderes
        }
    };
    

    Da stimmt doch konzeptionell was nicht. Und es ist kein hübscher Weg, durch immer mehr Ausnahmeregeln die Ausnahmen zu regeln und dabei noch mehr Ausnahmen zu provozieren.

    Interessanter wird die Sache beim Destruktor. Der kann in Ausdrücken verwendet werden.

    Ja, der ist auch (fast) eine ganz normale Methode. Nur wenige Sonderregeln, wie daß er Basisklassendestruktoren automatisch aufruft, den vptr ändert, implementiert werden muß selbst wenn pur virtuell seiend, und nicht überladen werden kann. Kann man wenigstens seine Adresse ziehen?


Anmelden zum Antworten