Standardkonstruktor in einem Konstruktoraufruf aufrufen



  • Hallo Community,

    ich habe ein Problem mit einem Konstruktoraufruf.
    Ich zeige zunaechst den Code (die Fragen stehen im Prinzip auch schon in den Kommentaren). Lasst euch nicht von den Templates verwirren, die haben (meine ich) nichts mit dem Problem zu tun. Ich bin nur beim lernen von Template-Programmierung drauf gestossen.

    #include <initializer_list>
    #include <iostream>
    
    using namespace std;
    
    struct MyStruct {
        int x;
        MyStruct (int x = 1) : x (x) {}
        void operator() () {
            // mach was mit x
        }
    };
    
    template<class T>
    class MyClass {
      public:
        MyClass (T const& t = MyStruct() ) : t (t) {}
    
        void doSomething() const {
            // mach was mit t
        }
      private:
        T t;
    };
    
    template<class T>
    void func (T t) {
        t();
    }
    
    int main() {
    
        MyClass<MyStruct> objA;                     // a) geht (wie erwartet)
        objA.doSomething();
    
        MyClass<MyStruct> objB();                   // b) geht nicht, (wie erwartet)
        objB.doSomething();
    
        MyClass<MyStruct> objC (MyStruct() );       // c) geht nicht, warum? d) und f) gehen doch auch !?
        objC.doSomething();
    
        MyClass<MyStruct> objD (MyStruct (42) );    // d) geht (wie erwartet)
        objD.doSomething();
    
        MyClass<MyStruct> objE { MyStruct() };    // e) geht (wie erwartet)
        objE.doSomething();
    
        func (MyStruct() );                         // f) geht (wie erwartet)
    
        return EXIT_SUCCESS;
    }
    

    a), b) und e) sind mir soweit eigentlich klar. Mein Problem ist, dass c) nicht geht, d) und f) aber schon. Was uebersehe ich da?

    Der Compiler meckert in den Zeilen 37 und 40:

    error C2228: Links von ".doSomething" muss sich eine Klasse/Struktur/Union befinden.

    Wenn ich diese Zeilen auskommentiere (also doSomething() fuer objB und objC nicht aufrufe), bekomme ich folgende Warnung:

    ...\main.cpp(37): warning C4930: 'MyClass<MyStruct> objB(void)': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)
    ...\main.cpp(40): warning C4930: 'MyClass<MyStruct> objC(MyStruct (__cdecl *)(void))': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)

    Soll das heissen, dass ich hier eine Funktion deklariert habe, die MyClass<MyStruct> zurueckgibt und als Parameter einen Zeiger auf eine Funktion erwartet, die ein MyStruct zurueckgibt?
    Das wuerde doch eigentlich so aussehen:

    MyClass<MyStruct> objC (MyStruct (*func) () );
    

    Aber vor allem wundert es mich, dass ich auf dieses Problem noch nicht frueher gestossen bin 😕

    Als IDE verwende ich Visual Studio 2013 mit entsprechendem Compiler (Toolset v120).

    Vielen Dank fuer eure Hilfe!

    Gruss
    Matze

    Edit: '=' bei objE entfernt



  • Das Problem ist bekannt als "Most Vexing Parse" und beschreibt eine Mehrdeutigkeit in der C++-Syntax. Und zwar werden die entsprechenden Variablendefinitionen als Funktionsdeklarationen erkannt.

    MatzeHHC schrieb:

    Lasst euch nicht von den Templates verwirren, die haben (meine ich) nichts mit dem Problem zu tun.

    Dann lass sie doch nächstes Mal weg. Ideal ist ein vollständiges, kompilierbares Minimalbeispiel, anhand dessen wir das Problem erkennen können.



  • Nexus schrieb:

    Das Problem ist bekannt als "Most Vexing Parse" und beschreibt eine Mehrdeutigkeit in der C++-Syntax. Und zwar werden die entsprechenden Variablendefinitionen als Funktionsdeklarationen erkannt.

    Danke, mein Problem war, dass ich nicht wusste, dass

    MyStruct()
    

    als namenloser Funktionszeiger interpretiert werden kann (stimmt das so 😕 )

    ich kannte nur

    MyStruct(*)()
    

    Sorry wegen der Templates...

    Gruß
    Matze



  • Kennste std::function?
    Da schreibste ja auch void() in den Parametern.



  • Nathan schrieb:

    Kennste std::function?
    Da schreibste ja auch void() in den Parametern.

    stimmt 😮



  • MatzeHHC schrieb:

    Danke, mein Problem war, dass ich nicht wusste, dass

    MyStruct()
    

    als namenloser Funktionszeiger interpretiert werden kann (stimmt das so 😕 )

    Nein, mit Funktionszeigern hat das nichts zu tun.

    MyClass<MyStruct> objC (MyStruct());
    

    ist aufgrund einer fragwürdigen Syntaxregel das gleiche wie

    MyClass<MyStruct> objC (MyStruct);
    

    was eine Funktionsdeklaration darstellt.

    Ich bin mir auch nicht sicher, wer es für eine gute Idee hielt, Klammern um Parametertypen zuzulassen. Oder generell um Typen in Deklarationskontexten.

    Nathan schrieb:

    Kennste std::function?
    Da schreibste ja auch void() in den Parametern.

    Das void() bedeutet was anderes als hier. Insbesondere ist es kein Funktionszeiger.



  • Nexus schrieb:

    MyClass<MyStruct> objC (MyStruct());
    

    ist aufgrund einer fragwürdigen Syntaxregel das gleiche wie

    MyClass<MyStruct> objC (MyStruct);
    

    was eine Funktionsdeklaration darstellt.

    Laut:

    MSVC schrieb:

    warning C4930: 'MyClass<MyStruct> objC(MyStruct (__cdecl *)(void))': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)

    scheint VC daraus aber:

    MyClass<MyStruct> objC(MyStruct (__cdecl *)(void))
    

    zu machen.
    Laut ideone auch: http://ideone.com/IH92h2

    Insbesondere ist es kein Funktionszeiger.

    Was dann?



  • Nexus schrieb:

    MatzeHHC schrieb:

    Danke, mein Problem war, dass ich nicht wusste, dass

    MyStruct()
    

    als namenloser Funktionszeiger interpretiert werden kann (stimmt das so 😕 )

    Nein, mit Funktionszeigern hat das nichts zu tun.

    MyClass<MyStruct> objC (MyStruct());
    

    ist aufgrund einer fragwürdigen Syntaxregel das gleiche wie

    MyClass<MyStruct> objC (MyStruct);
    

    was eine Funktionsdeklaration darstellt.

    Da verstehe ich meine Compiler-Warnung aber anders:

    Compiler schrieb:

    ...\main.cpp(40): warning C4930: 'MyClass<MyStruct> objC(MyStruct (__cdecl *)(void))': Funktion mit Prototyp wurde nicht aufgerufen (war eine Variablendefinition gemeint?)

    Und den Wikipediaeintrag:
    http://en.wikipedia.org/wiki/Most_vexing_parse

    Wikipedia schrieb:

    The line

    TimeKeeper time_keeper(Timer());
    

    could be disambiguated either as

    1. a variable definition for variable time_keeper of class TimeKeeper, passed an anonymous instance of class Timer or
    2. a function declaration for a function time_keeper which returns an object of type TimeKeeper and takes a single (unnamed) argument which is a function returning type Timer (and taking no input). (See Function object#In C and C++)

    Jetzt bin ich verwirrt 😕 😃



  • Ihr habt Recht, die Klammern stehen ja nach dem Parametertyp. Wie auch immer, jedenfalls wird die naheliegende Variante nicht bevorzugt 😉

    Nathan schrieb:

    Insbesondere ist es kein Funktionszeiger.

    Was dann?

    Eine Funktion.



  • Nexus schrieb:

    Nathan schrieb:

    Insbesondere ist es kein Funktionszeiger.

    Was dann?

    Eine Funktion.

    ...was im Kontext einer Funktionsdeklaration scheinbar dasselbe ist:
    http://ideone.com/3cPHMu


  • Mod

    Nathan schrieb:

    was im Kontext einer Funktionsdeklaration scheinbar dasselbe ist

    Du meinst wohl, im Kontext eines Funktionsparameters? Ist dasselbe wie mit Arrays

    After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.

    Nexus schrieb:

    Ein Funktionstyp.

    FTFY



  • Arcoth schrieb:

    Ist dasselbe wie mit Arrays

    After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.

    Stimmt, mit Arrays ist das ja gleich.


Log in to reply