Frage

Was genau sind die Regeln für die Konvertierung einer Operator=()-Zuweisung in C++ in eine Konstruktion?Wie zum Beispiel Foo foo = bar ruft tatsächlich den Konstruktor von Foo auf und akzeptiert bar als Argument, sofern vorhanden.Ich habe gegoogelt, wie das funktioniert, kann aber scheinbar nichts finden.

Ich habe ein Problem herauszufinden, warum die folgende Aufgabe versucht, einen Konstruktor zu verwenden, aber nicht den offensichtlich richtigen:HandlePtr( TYPE& Ressource ).Die Konstruktion mit der tatsächlichen Konstruktionssyntax funktioniert gut, jedoch nicht mit dem Zuweisungsoperator.

Code (offensichtlich der Kürze halber bearbeitet):

template< typename TYPE >
class HandlePtr {
public:
    HandlePtr( void ) = default;
    HandlePtr( HandlePtr< TYPE >& other ) = default;
    HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
    ~HandlePtr( void ) = default;

public:
    HandlePtr<TYPE>& operator=( TYPE& resource ) { return *this; }
    HandlePtr<TYPE>& operator=( HandlePtr<TYPE>& other ) { return *this; }
};

int main ( void ) {
    int x = 5;
    HandlePtr< int > g( x ); // works
    HandlePtr< int > i;i = x; // works
    HandlePtr< int > h = x; // doesn't work

            // also tried this just out of curiosity:
    HandlePtr< int > h = HandlePtr< int >( x ); // also does not work

    return 0;
}

Fehler:

shit.cpp: In function ‘int main()’:
try.cpp:19:24: error: no matching function for call to ‘HandlePtr<int>::HandlePtr(HandlePtr<int>)’
   HandlePtr< int > h = x; // doesn't work
                        ^
try.cpp:19:24: note: candidates are:
try.cpp:7:3: note: HandlePtr<TYPE>::HandlePtr(TYPE&) [with TYPE = int]
   HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
   ^
try.cpp:7:3: note:   no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘int&’
try.cpp:6:3: note: HandlePtr<TYPE>::HandlePtr(HandlePtr<TYPE>&) [with TYPE = int]
   HandlePtr( HandlePtr< TYPE >& other ) = default;
   ^
try.cpp:6:3: note:   no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘HandlePtr<int>&’
try.cpp:5:3: note: HandlePtr<TYPE>::HandlePtr() [with TYPE = int]
   HandlePtr( void ) = default;
   ^
try.cpp:5:3: note:   candidate expects 0 arguments, 1 provided
try.cpp:20:20: error: redeclaration of ‘HandlePtr<int> h’
   HandlePtr< int > h = HandlePtr< int >( x ); // also does not work
                    ^
try.cpp:19:20: error: ‘HandlePtr<int> h’ previously declared here
   HandlePtr< int > h = x; // doesn't work
War es hilfreich?

Lösung

Das übersehen Sie im Erklärung:

T t = u;

Dies ist nicht der Zuweisungsoperator. t = u; ist kein Unterausdruck einer Deklaration.Der einzige Ausdruck hier ist u;und das Ergebnis der Auswertung des Ausdrucks u wird als Initialisierer für das Objekt verwendet t deklariert wird.

Wenn u Typ hat T, Dann t ist kopierkonstruiert aus u.

Wenn u hat keinen Typ T, Dann u muss zunächst in Typ konvertiert werden T.Dadurch entsteht ein Wert vom Typ T.

Sie haben also keine Konstruktoren, die einen R-Wert akzeptieren T t = u;, und das Identische T t = T(u); beide scheitern.Jedoch, T t(u) ist erfolgreich, weil kein R-Wert erstellt wird;der Wert u wird als Argument für den Konstruktor verwendet T(U &).

Vereinfachtes Codebeispiel:

struct T
{
    T(int &);
    T(T&);
    T();
    T &operator=(int &);
};

int main()
{
    int x = 5;
    T g(x);   // OK, T(int &)
    T g2(5);   // fail, looks for T(int const &)
    T i;      // OK, T()
    i = x;    // OK, T::operator=(int&)
    T h3 = i; // OK, T(T&)
    T h1 = T(x);    // fail, looks for T(T const &)
    T h2 = x;       // fail, identical to previous line 
}

Normalerweise sollten Sie verwenden const & als Parameter für Kopierkonstruktoren und Zuweisungsoperatoren;dann werden alle diese „fehlgeschlagenen“ Fälle zu „OK“, da ein R-Wert an eine konstante Referenz gebunden werden kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top