2016-12-28 4 views
0

Mein C++ - Compiler ist C++ 14. Ich habe eine Funktion, die ein Objekt einer benutzerdefinierten Klasse einbezieht, die alle Arten von Fehlercodes einkapselt. Dieser Parameter wird als Referenz übergeben. Das benutzerdefinierte Klassenobjekt wird manchmal mit einem gültigen Fehlerwert & gefüllt, manchmal kann es leer sein. Ich habe eine nette neue Sache in C++ 14 gefunden, die std::experimental::optional ist. Jetzt versuche ich dies für meinen Parameter zu verwenden, da es wirklich ein optional Parameter ist.Verwendung von std :: experimental :: optional als Parameter als Referenz

Nach meiner Funktion Unterschrift mit std :: ist experimentell :: optional, dass ich zu verwenden, versuchen:

MyFunction(some param, std::experimental::optional<MyCustomErrorClass> & error_code) { 

    //some logic 
    //sometimes error_code is populated & sometimes not populated 
} 

Es folgt, wie ich rufe MyFunction:

MyCustomErrorClass error_code_object; 
MyFunction(some_param, error_code_object); 

Ich erhalte jedoch den folgenden Compilerfehler:

error: non-const lvalue reference to type 'std::experimental::optional< MyCustomErrorClass>' cannot bind to a value of unrelated type 'MyCustomErrorClass' MyFunction(some_param, error_code_object); 

Ich habe versucht, eine Menge zu suchen. Die meisten der Anwendungsbeispiele std::experimental::optional oder std::optional demonstrieren es als Rückgabewert von Funktionen.

Was ist los mit meiner Verwendung von std :: experimental :: optional?

+0

_Warum wird 'error_code' von einer nichtkonstanten Referenz übergeben? Wenn es nur ein Eingabeparameter ist, übergeben Sie es mit const-ref genauso wie mit jedem anderen Parameter ... – ildjarn

+0

C++ 14 ist ein Standard. Bitte verwenden Sie bei der Beschreibung Ihres Compilers den Namen, die Versionsnummer und die Plattform. –

+0

@LightnessRacesinOrbit Tut mir leid. Mein Code ist in den Fenstern clang, gcc und microsoft kompiliert. alle 3. –

Antwort

2

Dies ist nicht über std::experimental::optional; Es geht darum, ein temporäres an eine Lvalue-Referenz zu binden, was nicht möglich ist.

Das temporäre ist das Ergebnis der impliziten Konvertierung von MyCustomErrorClass zu optional<MyCustomErrorClass>.

Ein richtiges MCVE für Ihr Problem folgt:

void f(long&); 

int main() 
{ 
    int x = 42; 
    f(x); 
} 

// error: invalid initialization of non-const reference of type 'long int&' from an 
//   rvalue of type 'long int' 

Implizite Konvertierung zwischen int und long möglich ist, aber die resultierende temporäre nicht auf eine L-Wert-Referenz binden.

Stattdessen das Objekt optional vorkonstruieren und namentlich übergeben.

optional<MyCustomErrorClass> opt_error_code_object = MyCustomErrorClass{}; 
MyFunction(some_param, opt_error_code_object); 
+0

aber mit dem param optional, bin ich in der Lage, den Code genau so zu kompilieren. Entfernen Sie einfach das optionale from param und übergeben Sie stattdessen ein normales "MyCustomErrorClass" -Objekt. –

+0

@SegmentationFault: Ja, natürlich. Wenn die Typen an erster Stelle übereinstimmen, ist keine implizite Konvertierung erforderlich, sodass Sie eine Referenz an das tatsächliche Objekt und nicht an eine temporäre übergeben. Genau wie wenn ich "f" oben machen würde, nehme ich "int &" statt "long &". Sie haben Schwierigkeiten, wenn die Typen nicht gleich sind. –

1

Sie geben Ihrer Funktion keine optionale MyCustomErrorClass, Sie geben es eine nicht optionale MyCustomErrorClass. Und Sie geben es als Referenz, was bedeutet, dass Sie versuchen können, es zu mutieren, und es wird versuchen, das übergebene Objekt zu mutieren. Aber Sie können keine veränderbaren optional<T> Operationen auf etwas ausführen, das tatsächlich nicht optional<T> ist (gut, ich Angenommen, du könntest es, wenn du wirklich, wirklich willst ... aber schlimme Dinge passieren Leuten, die so etwas tun).

+0

Fast, aber nicht ganz. –

2

Sie möchten hier keine optionale Referenz verwenden.

Ein Verweis auf ein optional ist ein ganz anderes Tier, das eine optionale Referenz; das zweite wurde nicht in C++ 17 gewählt, weil es eine verwirrende Semantik hat, aber es wäre näher an dem, was Sie wollen.

Eine optionale speichert ein kopieren seiner Daten in sich.Ein Verweis auf ein Optional ist somit ein Verweis auf einen Container, der eine Kopie des Objekts enthält.

Wenn Sie Ihr Fehlerobjekt an die Funktion übergeben, die einen Verweis auf einen optionalen Fehlertyp erwartet, kopiert es zuerst das Fehlerobjekt in ein temporäres optionales Objekt. Dann versucht es das Temporäre an einen (lvalue) Verweis zu binden; das ist illegal. Dein Code kann also nicht kompiliert werden.

Wenn Sie es "reparieren", indem Sie ein nicht-temporäres Optional erstellen oder das Temporäre in einen Lvalue umwandeln, erhalten Sie wahrscheinlich immer noch nicht, was Sie wollen, weil die Funktion jetzt mit der Kopie innerhalb des optionalen interagiert, nicht die ursprüngliches Fehlerobjekt

Wenn Sie ein Objekt als Referenz übergeben, möchten Sie normalerweise, dass Änderungen ausgegeben werden. Aber sie werden sich nicht über die Kopie innerhalb des Optional hinaus fortpflanzen.

Eine Lösung ist ein MyCustomErrorClass* - ein Zeiger zu nehmen. Dies ist Nullable (wie ein optionales) und speichert keine Kopie. Fügen Sie einfach eine & an der aufrufenden Website hinzu, und verwenden Sie nullptr, wenn Sie nicht übergeben möchten.

Verwandte Themen