2012-06-26 12 views
55

C++ 11 unterstützt eine neue Funktion Syntax:Soll der nachgestellte Rückgabetypsyntaxstil der Standard für neue C++ 11-Programme werden?

auto func_name(int x, int y) -> int; 

Derzeit würde diese Funktion als deklariert werden:

int func_name(int x, int y); 

Der neue Stil scheint nicht weit noch angenommen werden (etwa in den gcc stl)

Sollte aber dieser neue Stil überall in neuen C++ 11-Programmen bevorzugt oder nur bei Bedarf verwendet werden?

Persönlich bevorzuge ich den alten Stil, wenn möglich, aber eine Code-Basis mit gemischten Stilen sieht ziemlich hässlich aus.

+23

Es ist dort meist für 'declltype' in Argumenten. –

+0

was CatPlusPlus sagt: macht in Ihrem Beispiel wenig Sinn – stijn

+0

@Cat Plus Plus Das bedeutet, dass Sie die Dinge so belassen, wie sie in C++ 03 sind, es sei denn, Sie müssen den Rückgabetyp ableiten? – mirk

Antwort

71

In bestimmten Fällen müssen Sie einen abschließenden Rückgabetyp verwenden. Vor allem muss ein Lambda-Rückgabetyp, falls angegeben, über einen abschließenden Rückgabetyp angegeben werden. Wenn Ihr Rückgabetyp eine decltype verwendet, die erfordert, dass die Argumentnamen im Gültigkeitsbereich sind, muss ein abschließender Rückgabetyp verwendet werden (normalerweise kann jedoch declval<T> verwendet werden, um dieses letzte Problem zu umgehen).

Der abschließende Rückgabetyp hat einige andere geringfügige Vorteile. Um zum Beispiel einer nicht-Inline-Funktionsdefinition mit der herkömmlichen Funktion Syntax beachten:

struct my_awesome_type 
{ 
    typedef std::vector<int> integer_sequence; 

    integer_sequence get_integers() const; 
}; 

my_awesome_type::integer_sequence my_awesome_type::get_integers() const 
{ 
    // ... 
} 

Mitglied typedefs ist in ihrem Umfang nicht erst nach dem Name der Klasse erscheint vor ::get_integers, so müssen wir die Klasse Qualifikation zweimal wiederholen . Wenn wir eine Hinterrückgabetyp verwenden, brauchen wir nicht den Namen des Typs zu wiederholen:

auto my_awesome_type::get_integers() const -> integer_sequence 
{ 
    // ... 
} 

In diesem Beispiel ist es nicht so eine große Sache, aber wenn man lange Klassennamen oder Elementfunktionen Klassenvorlagen, die nicht inline definiert sind, können die Lesbarkeit erheblich beeinflussen.

In seiner "Fresh Paint" Sitzung in C++ Now 2012 wies Alisdair Meredith darauf hin, dass, wenn Sie Rückgabetypen konsequent verwenden Hinter, die Namen aller Ihre Funktionen ordentlich aufreihen:

auto foo() -> int; 
auto bar() -> really_long_typedef_name; 

ich verwendet habe, Trailing Rückgabetypen überall in CxxReflect, wenn Sie also nach einem Beispiel dafür suchen, wie Code sieht, sie konsistent zu verwenden, können Sie einen Blick dorthin werfen (zB the type class).

+1

Es sieht nicht so aus, als ob es einen Konsens gibt, aber es ist interessant, CxxReflect mit dem neuen Stil zu betrachten. – mirk

+0

Hallo, James. Diese Antwort könnte angesichts des C++ 14-Standards wahrscheinlich genauer gemacht werden. –

6

diesen schönen Artikel: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Sehr gutes Beispiel, wenn diese Syntax ohne decltype in Spiel zu verwenden:

class Person 
{ 
public: 
    enum PersonType { ADULT, CHILD, SENIOR }; 
    void setPersonType (PersonType person_type); 
    PersonType getPersonType(); 
private: 
    PersonType _person_type; 
}; 

auto Person::getPersonType() -> PersonType 
{ 
    return _person_type; 
} 

und brillante Erklärung auch von Alex Allain Artikel gestohlen „Weil der Rückgabewert am Ende geht von Anstatt die Funktion zu verwenden, müssen Sie den Klassenbereich nicht hinzufügen."

zu diesem möglichen Fall vergleichen, wenn man zufällig über Klassenbereich vergessen, und für größere Katastrophe, eine andere person in globalem Bereich definiert ist:

typedef float PersonType; // just for even more trouble 
/*missing: Person::*/ 
PersonType Person::getPersonType() 
{ 
    return _person_type; 
} 
+5

Ich bin nicht sicher, dass dies in die Kategorie "Katastrophe" fällt: Wenn der Typ falsch ist, wird der Code nicht kompilieren. Laufzeitfehler können verheerende Folgen haben; Kompilierzeitfehler, nicht so sehr. –

+2

@JamesMcNellis vergleichen Sie die Compiler-Ausgabe: 'prog.cpp: 13: 12: Fehler: Prototyp für 'PersonType Person :: getPersonType()' passt nicht zu Klasse 'Person'' vs ' prog.cpp: 13: 1: Fehler: 'PersonType' nennt keinen Typ' Der erste Fehler vom Compiler ist, zumindest für mich, schlechter zu verstehen. – PiotrNycz

46

Zusätzlich zu dem, was anderen gesagt, die hinteren Rückkehr geben Sie ermöglicht auch this zu verwenden, die

struct A { 
    std::vector<int> a; 

    // OK, works as expected 
    auto begin() const -> decltype(a.begin()) { return a.begin(); } 

    // FAIL, does not work: "decltype(a.end())" will be "iterator", but 
    // the return statement returns "const_iterator" 
    decltype(a.end()) end() const { return a.end(); } 
}; 

In der zweiten Erklärung erlaubt nicht anders ist, wir den traditionellen Stil verwendet. da jedoch this nicht an dieser Position erlaubt ist, die Compiler d oes verwenden es nicht implizit. So verwendet die a.end() den statisch deklarierten Typ von a zu bestimmen, was end Überladung von vector<int> es wird aufrufen, die endet, die nicht-const-Version.

7

Ein weiterer Vorteil ist, dass die Syntax des schleppenden Rückgabetyps besser lesbar ist, wenn die Funktion einen Zeiger auf eine Funktion zurückgibt. Zum Beispiel vergleichen

void (*get_func_on(int i))(int); 

mit

auto get_func_on(int i) -> void (*)(int); 

Allerdings kann man argumentieren, dass eine bessere Lesbarkeit einfach durch die Einführung einer Art Alias ​​für den Funktionszeiger erreicht werden kann:

using FuncPtr = void (*)(int); 
FuncPtr get_func_on(int i);