return in Listeninitialisierer

Gast #7089599
Lesenswert?

Wozu dienen hier die zwei Zeilen mit dem return A() ?
1
#include <iostream>
2

3
class A {
4
public:
5
    void foo() const { std::cout << "A::foo() const\n"; }
6
    void foo() { std::cout << "A::foo()\n"; }
7
};
8

9
A bar() { return A(); }
10
const A cbar() { return A(); }
11

12

13
int main()
14
{
15
    bar().foo();  // calls foo
16
    cbar().foo(); // calls foo const
17
}

Warum nicht so?
1
#include <iostream>
2

3
class A {
4
public:
5
    void foo() const { std::cout << "A::foo() const\n"; }
6
    void foo() { std::cout << "A::foo()\n"; }
7
};
8

9

10
int main()
11
{
12
    A bar;
13
    const A cbar;
14

15
    bar.foo();  // calls foo
16
    cbar.foo(); // calls foo const
17
}

(eigentlich dient der Code zur Veranschaulichung CV-qualifizierter 
r-values)
#7089633
Lesenswert?

Markus schrieb:
> Warum nicht so?

Der erste Fall ruft foo über Funktionen (const/nicht const) auf, deine 
Lösung dagegen über Variablen (const/nicht const).

Auch wenn es ähnliche aussieht, ist das nicht das selbe. Das const 
steckt da an verschiedenen Stellen.

Ob das für den Demonstrations- und Lerneffekt wichtig ist, keine Ahnung. 
Da fehlt der Kontext des Beispiels.

Oliver
#7090652
Lesenswert?

Was hat das Thema mit Listen zu tun?

Meinst Du wirklich die Unterscheidung ro/rw bei return-Werten?

Oder meinst Du die ref-Qualifikation von Elementfunktion? Also, ob eine 
Elementfunktion auf ein rvalue oder lvalue anwendbar ist (ich meine 
nicht die Parameterliste).

Ersteres ist bei primitiven DT sinnlos und bei UDT ggf. schlecht, weil 
es ein move ggf. verhindert.
Gast #7090763
Lesenswert?

Wilhelm M. schrieb:
> Was hat das Thema mit Listen zu tun?

Gar nichts, ich wußte nicht, welcher Titel am besten paßt: Anstatt
1
A bar() { return A(); }
 las ich
1
A bar { return A(); }
 und wunderte mich über das { return A(); }. Wie nennst du hier die 
geschweiften Klammern?
Mit dem eigentlichen Thema des Beispiels hat meine Frage gar nichts zu 
tun, denn:

> Meinst Du wirklich die Unterscheidung ro/rw bei return-Werten?

Darauf läuft es im Buch hinaus, Überladen von const und nicht-const.
Zuvor muß ich aber lvalues und rvalues verstehen...


> Oder meinst Du die ref-Qualifikation von Elementfunktion? Also, ob eine
> Elementfunktion auf ein rvalue oder lvalue anwendbar ist (ich meine
> nicht die Parameterliste).
> Ersteres ist bei primitiven DT sinnlos und bei UDT ggf. schlecht, weil
> es ein move ggf. verhindert.

Was immer damit gemeint sein mag, ich bin davon noch weit entfernt ;-)
#7090845
Lesenswert?

Markus schrieb:
> Wilhelm M. schrieb:
>> Was hat das Thema mit Listen zu tun?
>
> Gar nichts, ich wußte nicht, welcher Titel am besten paßt:

Dann wundere Dich nicht über wenige Beiträge zum eigentlichen Thema ;-)

> Anstatt
1
A 
2
> bar() { return A(); }
 las ich
1
A bar { return A(); }
 und
> wunderte mich über das { return A(); }. Wie nennst du hier die
> geschweiften Klammern?

Der Funktionskörper ist ein Block: die geschweiften Klammen sind die 
Block-Begrenzer.

>> Meinst Du wirklich die Unterscheidung ro/rw bei return-Werten?
>
> Darauf läuft es im Buch hinaus, Überladen von const und nicht-const.

Bzgl. des Rückgabetyps kannst Du in C++ nicht überladen: der Typ der 
Funktion ist nicht Bestandteil der Signatur, deswegen ist solches 
Vorgehen kein korrektes Überladen.

Von Überladen spricht man, wenn die Signatur sich unterscheidet, aber 
der Name (Bestandteil der Signatur) gleich bleibt:
1
void f();
2
void f(int);

oder
1
struct A {
2
   voif f();
3
   voif f() const;
4
};

> Zuvor muß ich aber lvalues und rvalues verstehen...

Betrachte rvalues als temporäre-anonyme Objekte.

>> Oder meinst Du die ref-Qualifikation von Elementfunktion? Also, ob eine
>> Elementfunktion auf ein rvalue oder lvalue anwendbar ist (ich meine
>> nicht die Parameterliste).
>> Ersteres ist bei primitiven DT sinnlos und bei UDT ggf. schlecht, weil
>> es ein move ggf. verhindert.
>
> Was immer damit gemeint sein mag, ich bin davon noch weit entfernt ;-)

Ok, dann vergiss es fürs erste. Es geht um:
1
struct A {
2
    void f() &; 
3
    void f() &&;
4
};
5

6
A foo();
Im ersten Fall muss das Objekt, für dass f() aufgerufen wird (bspw: 
a.f()) ein lvalue sein, im zweiten Fall ein rvalue (bspw: foo().f() ).
Gast #7090903
Lesenswert?

Ich weiß nicht was sich der Autor dabei gedacht hat:

Markus schrieb:
1
const A cbar() { return A(); }

Const für einen Rückgabewert auf ein Value (also keine Referenz/Pointer) 
macht keinen Sinn. Zumindest ist mir kein Fall bekannt und ich habe noch 
von keinem Fall gelesen, wo es sinnvoll ist. Außer natürlich wie hier um 
clever zu demonstrieren wann nicht/const Funktionen aufgerufen werden. 
/Ironie

Z.B. 
https://www.sandordargo.com/blog/2020/11/18/when-use-const-3-return-types

Aber selbst Scott Meyers war damals drauf reingefallen (in seinem Buch) 
und hat es erst später korrigiert. ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren