Was heißt: warning: type qualifiers ignored on function return type ?
-
Hallo zusammen,
ich stehe gerade etwas geistig auf dem Schlauch, ich habe folgende Fehlermeldung:
warning: type qualifiers ignored on function return type
Die entsteht in der Zeile:
const State getLocalState() const;
Ich sehe den Wald vor lauter Bäumen gerade nicht. Kann mich jemand draufstoßen?
sven
-
Was soll das const denn hier bewirken? Der Rückgabewert ist eine Kopie eines State-Objekts, wieso sollte die Funktion dem Benutzer vorschreiben können, was er mit seiner Kopie machen darf und was nicht?
-
ha, stimmt. da fehlt das &. Nun ja, ich sagte ja, ich steh heut auf dem Schlauch ;).
Vielen Dank.
-
Ist State ein typedef auf einen primitiven Typ, oder eine Klasse?
Edit: Ok, die Frage ist eigentlich nur im Kontext mit Operator Overloading relevant, im Falle einer normalen Funktion ist ein top level const am Returntype in der Tat sinnlos...
-
SeppJ schrieb:
Was soll das const denn hier bewirken? Der Rückgabewert ist eine Kopie eines State-Objekts, wieso sollte die Funktion dem Benutzer vorschreiben können, was er mit seiner Kopie machen darf und was nicht?
Würde es im Zusammenhang mit C++11 nicht doch Sinn machen? Also wenn man ein Objekt zurückgeben möchte, aber das Objekt intern durch die zurückgebende Klasse weiter verwendet wird, so dass der move-Constructor nicht aufgerufen werden darf, sondern nur der Copy-Constructor?
-
Das Objekt, das hier zurückgegeben wird, ist eine Kopie und keine Referenz. Es kann sich niemals um das selbe Objekt handeln, das irgendeine Klasse "intern verwendet" und es wäre in jedem Fall sicher, daraus zu moven (außer natürlich die Implementierung der Klasse macht irgendeinen argen Blödsinn)...
-
dot schrieb:
Das Objekt, das hier zurückgegeben wird, ist eine Kopie und keine Referenz. Es kann sich niemals um das selbe Objekt handeln, das irgendeine Klasse "intern verwendet" und es wäre in jedem Fall sicher, daraus zu moven (außer natürlich die Implementierung der Klasse macht irgendeinen argen Blödsinn)...
Wieso? Wenn ich eine member-Variable der Klasse zurückliefere?
Normalerweise würde dann, falls vorhanden der Move-Constructor aufgerufen, wodurch meine Member-Variable 'kaputt' gehen könnte...
-
XSpille schrieb:
dot schrieb:
Das Objekt, das hier zurückgegeben wird, ist eine Kopie und keine Referenz. Es kann sich niemals um das selbe Objekt handeln, das irgendeine Klasse "intern verwendet" und es wäre in jedem Fall sicher, daraus zu moven (außer natürlich die Implementierung der Klasse macht irgendeinen argen Blödsinn)...
Wieso? Wenn ich eine member-Variable der Klasse zurückliefere?
Normalerweise würde dann, falls vorhanden der Move-Constructor aufgerufen, wodurch meine Member-Variable 'kaputt' gehen könnte...Ähm, nein!?
X blub() { return my_x; }
Wo wird hier ein Move Konstruktor aufgerufen?
-
XSpille schrieb:
Wieso? Wenn ich eine member-Variable der Klasse zurückliefere?
Tust du ja auf keinen Fall, höchstens eine Referenz auf die Member-Variable...
-
dot schrieb:
Wo wird hier ein Move Konstruktor aufgerufen?
Irrtum meinerseits
Habs gerade auch getestet.test.cpp:32:10: error: use of deleted function 'constexpr Foo::Foo(const Foo&)'
test.cpp:4:8: note: 'constexpr Foo::Foo(const Foo&)' is implicitly declared as deleted because 'Foo' declares a move constructor or move assignment operatorpumuckl schrieb:
XSpille schrieb:
Wieso? Wenn ich eine member-Variable der Klasse zurückliefere?
Tust du ja auf keinen Fall, höchstens eine Referenz auf die Member-Variable...
Stimmt... Gute Begründung...
Naja... Dann fällt mir doch kein Sinn für das const ein
-
XSpille schrieb:
dot schrieb:
Wo wird hier ein Move Konstruktor aufgerufen?
Irrtum meinerseits
Wenn my_x eine lokale Variable wäre, würde, falls vorhanden, der Move Konstruktor aufgerufen. Aber in dem Fall ist das auch safe...
-
dot schrieb:
Ist State ein typedef auf einen primitiven Typ, oder eine Klasse?
Edit: Ok, die Frage ist eigentlich nur im Kontext mit Operator Overloading relevant, im Falle einer normalen Funktion ist ein top level const am Returntype in der Tat sinnlos...
Das ist nicht nur bei Operator Overlöding interessant, sondern auch bei sowas
getLocalState() = Blubb; // geht mit "UDT getLocalState()", geht nicht mit "const UDT getLocalState()"
Finde ich aber grässlich.
In C++11 kann man das wesentlich schöner verhindern indem man den Zuweisungsoperator "&" macht (alsoUDT& operator = (ARG) & {...
schreibt, und damit verbietet dassthis
an eine rvalue gebunden wird).
-
hustbaer schrieb:
dot schrieb:
Ist State ein typedef auf einen primitiven Typ, oder eine Klasse?
Edit: Ok, die Frage ist eigentlich nur im Kontext mit Operator Overloading relevant, im Falle einer normalen Funktion ist ein top level const am Returntype in der Tat sinnlos...
Das ist nicht nur bei Operator Overlöding interessant, sondern auch bei sowas
getLocalState() = Blubb; // geht mit "UDT getLocalState()", geht nicht mit "const UDT getLocalState()"
Tatsächlich, ich hab mir irgendwie immer eingebildet, dass ein solcher Function Call ein rvalue wäre...
hustbaer schrieb:
In C++11 kann man das wesentlich schöner verhindern indem man den Zuweisungsoperator "&" macht (also
UDT& operator = (ARG) & {...
schreibt, und damit verbietet dassthis
an eine rvalue gebunden wird).Nanu, wie nennt sich diese Syntax denn, das hab ich noch nie gesehn und im Standard und bei google kann ich irgendwie auch nix dazu finden!?
-
Das nennt sich Ref-Qualifier, wird aber bei den Compilern als "Rvalue References for *this" gelistet. http://stackoverflow.com/questions/8610571/what-is-rvalue-reference-for-this
-
Sehr interessantes Feature das mir bisher unbekannt war, danke für den Hinweis!
-
dot schrieb:
hustbaer schrieb:
dot schrieb:
Ist State ein typedef auf einen primitiven Typ, oder eine Klasse?
Edit: Ok, die Frage ist eigentlich nur im Kontext mit Operator Overloading relevant, im Falle einer normalen Funktion ist ein top level const am Returntype in der Tat sinnlos...
Das ist nicht nur bei Operator Overlöding interessant, sondern auch bei sowas
getLocalState() = Blubb; // geht mit "UDT getLocalState()", geht nicht mit "const UDT getLocalState()"
Tatsächlich, ich hab mir irgendwie immer eingebildet, dass ein solcher Function Call ein rvalue wäre...
Ist es ja auch (das Ergebnis des Funktionsaufrufs, der Funktionsaufruf selbär ist gar keine Value sondern ein Funktionsaufruf :D).
Nur darf man Memberfunktionen per Default auf RValues aufrufen. Sonst würdeFunktion().AndereFunktion()
nicht gehen. Geht aber. So lange manAndereFunktion
nicht Ref-qualifiziert.Und da der
operator =
bei UDTs per Default ne Memberfunktion ist, kann man auchFunktion().operator = (blubb)
schreiben -- undFunktion() = blubb
ist ja genau das selbe, bloss anders geschrieben.Ergo geht es.
Sobald man dann
operator =
ref-qualifizierterweise selbst definiert, geht es nimmer.BTW: Angenommen man möchte den
operator =
ref-qualifiziert haben, aber sonst nix ändern (also genau die Implementierung die der Compiler von sich aus machen würde)...
Für den Fall würde sich jaUDT& operator = (UDT const&) & = default;
als Syntax anbieten.
Weiss jmd. ob das erlaubt ist? Würde im Falle des Falles nämlich viel sinnlose Tipperei ersparen und hätte dank Wartungsfreiheit auch ein geringeres Fehlerpotential (Membervariable dazumachen, nicht anoperator =
denken -> Problem).
-
hustbaer schrieb:
Ist es ja auch (das Ergebnis des Funktionsaufrufs, der Funktionsaufruf selbär ist gar keine Value sondern ein Funktionsaufruf :D).
Naja, ich meinte natürlich den Wert der Function Call Expression...
hustbaer schrieb:
Nur darf man Memberfunktionen per Default auf RValues aufrufen. Sonst würde
Funktion().AndereFunktion()
nicht gehen. Geht aber. So lange manAndereFunktion
nicht Ref-qualifiziert.Und da der
operator =
bei UDTs per Default ne Memberfunktion ist, kann man auchFunktion().operator = (blubb)
schreiben -- undFunktion() = blubb
ist ja genau das selbe, bloss anders geschrieben.Ergo geht es.
Sobald man dann
operator =
ref-qualifizierterweise selbst definiert, geht es nimmer.Ach, stupid me, natürlich. Aber wenn ich das richtig sehe, braucht man im klassischen Paradebeispiel immer noch ein top level const am Return Type:
vector3d operator +(const vector3d& a, const vector3d& b); (x + y) = stuff; // kompiliert fröhlich vor sich hin
hustbaer schrieb:
BTW: Angenommen man möchte den
operator =
ref-qualifiziert haben, aber sonst nix ändern (also genau die Implementierung die der Compiler von sich aus machen würde)...
Für den Fall würde sich jaUDT& operator = (UDT const&) & = default;
als Syntax anbieten.
Weiss jmd. ob das erlaubt ist? Würde im Falle des Falles nämlich viel sinnlose Tipperei ersparen und hätte dank Wartungsfreiheit auch ein geringeres Fehlerpotential (Membervariable dazumachen, nicht anoperator =
denken -> Problem).Ich denke schon:
ISO/IEC 14882:2011 §8.4.2/1 schrieb:
[...] have the same declared function type (except for possibly differing ref-qualifiers and except that in the case of a copy constructor or copy assignment operator, the parameter type may be "reference to non-const T", where T is the name of the member function's class) as if it had been implicitly declared, [...]
-
Wie waere es mit:
T& operator = (T const&) && = delete;
-
Ah natürlich, der ref-qualifier gehört ja zur Signatur, nice!
Jetzt wär nur noch interessant, ob man mehr als eine Variante von operator = als defaulted definieren kann, wenn der Unterschied nur den ref-qualifier betrifft!? Ich vermute mal ja!?
-
dot schrieb:
Aber wenn ich das richtig sehe, braucht man im klassischen Paradebeispiel immer noch ein top level const am Return Type:
vector3d operator +(const vector3d& a, const vector3d& b); (x + y) = stuff; // kompiliert fröhlich vor sich hin
Wenn vector3d einen "&" qualifizierten operator = hat darf das eigentlich nicht sein. (Ohne geht es natürlich, ging immer, war auch immer schon etwas komisch. Aber naja, real hab ich in > 12 Jahren damit noch nie ein Problem gehabt.)
Gerade ausprobiert mit clang online:
struct foo { foo() {} }; foo operator + (const foo&, const foo&) { return foo(); } struct bar { bar() {} bar& operator = (bar const&) & = default; }; bar operator + (const bar&, const bar&) { return bar(); } int main() { foo a, b, c; bar x, y, z; (a + b) = c; // OK (x + y) = z; // error: no viable overloaded '=' // (x + y) = z; // ~~~~~~~ ^ ~ }
----
Kellerautomat schrieb:
Wie waere es mit:
T& operator = (T const&) && = delete;
Das sollte unnötig sein. Wenn man nen
T& operator = (T&)
definiert bekommt man ja auch keinen implizit definiertenT& operator = (const T&)
dazu.
Genau so bekommt man keinen implizit definiertenT& operator = (const T&)
dazu wenn manT& operator = (const T&) &
selbst definiert hat.