Haruskah gaya sintaks tipe hasil akhir menjadi default untuk program C ++ 11 baru? [Tutup]


92

C ++ 11 mendukung sintaks fungsi baru:

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

Saat ini fungsi ini akan dideklarasikan sebagai:

int func_name(int x, int y);

Gaya baru tampaknya belum diadopsi secara luas (katakanlah di gcc stl)

Namun, haruskah gaya baru ini lebih disukai di mana pun di program C ++ 11 baru, atau apakah itu hanya akan digunakan saat diperlukan?

Secara pribadi, saya lebih suka gaya lama jika memungkinkan, tetapi basis kode dengan gaya campuran terlihat cukup jelek.


29
Itu ada sebagian besar untuk decltypeargumen.
Cat Plus Plus

apa yang CatPlusPlus katakan: tidak masuk akal menggunakannya dalam contoh Anda
stijn

@Cat Plus Plus Ini berarti bahwa Anda membiarkan hal-hal seperti di C ++ 03, kecuali jika Anda perlu menurunkan tipe kembalian?
mirk

1
Jelek harus menentukan "otomatis" di depan setiap fungsi. Apakah itu seperti jawaban cabul C ++ untuk "def" python?
Erik Aronesty

Jawaban:


110

Ada kasus tertentu di mana Anda harus menggunakan jenis pengembalian jejak. Terutama, jenis pengembalian lambda, jika ditentukan, harus ditentukan melalui jenis pengembalian tambahan. Selain itu, jika tipe pengembalian Anda menggunakan decltypeyang mengharuskan nama argumen berada dalam cakupan, tipe pengembalian jejak harus digunakan (namun, biasanya dapat digunakan declval<T>untuk mengatasi masalah yang terakhir ini).

Jenis trailing return memang memiliki beberapa keuntungan kecil lainnya. Misalnya, pertimbangkan definisi fungsi anggota non-inline menggunakan sintaks fungsi tradisional:

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
{
    // ...
}

Anggota typedefs tidak berada dalam lingkup sampai nama kelas muncul sebelumnya ::get_integers, jadi kita harus mengulang kualifikasi kelas dua kali. Jika kita menggunakan tipe pengembalian jejak, kita tidak perlu mengulangi nama tipe:

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

Dalam contoh ini, ini bukan masalah besar, tetapi jika Anda memiliki nama kelas yang panjang atau fungsi anggota template kelas yang tidak ditentukan secara inline, hal ini dapat membuat perbedaan besar dalam keterbacaan.

Dalam sesi "Fresh Paint" di C ++ Now 2012, Alisdair Meredith menunjukkan bahwa jika Anda menggunakan tipe pengembalian trailing secara konsisten, nama semua fungsi Anda berbaris rapi:

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

Saya sudah digunakan mengikuti tipe kembali mana-mana di CxxReflect , jadi jika Anda sedang mencari contoh bagaimana kode terlihat menggunakan mereka secara konsisten, Anda dapat melihat ada (misalnya, yang typekelas ).


1
Sepertinya belum ada konsensus, tetapi menarik untuk melihat CxxReflect dengan gaya baru.
mirk

Hai, James. Jawaban ini mungkin bisa dibuat lebih akurat dengan mempertimbangkan standar C ++ 14.
Drew Dormann

@DrewDormann Apa yang akan Anda tambahkan / ubah?
underscore_d

Alignment sebenarnya adalah nilai tambah yang besar, sampai-sampai saya berharap akan ada kata kunci 'func' baru untuk menggantikan 'auto' yang tidak berarti di sini.
Johan Boulé

67

Selain apa yang orang lain katakan, tipe kembali trailing juga memungkinkan untuk digunakan this, yang sebaliknya tidak diperbolehkan

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(); }
};

Dalam deklarasi kedua, kami menggunakan gaya tradisional. Namun karena thistidak diperbolehkan pada posisi itu, kompilator tidak menggunakannya secara implisit. Jadi a.end()penggunaan jenis yang dideklarasikan secara statis auntuk menentukan endkelebihan beban apa vector<int>yang akan dipanggil, yang akhirnya menjadi versi non-const.


2
Meskipun ini adalah demonstrasi konsep yang baik / rapi (menggunakan anggota dalam tipe kembali), itu lucu karena dalam C ++ 14 menentukan tipe sama sekali berlebihan dalam definisi sebaris tanpa konversi; kita sekarang bisa menggunakan deduksi tipe pengembalian penuh. : P
underscore_d

27

Keuntungan lainnya adalah sintaks tipe trailing-return bisa lebih mudah dibaca ketika fungsi mengembalikan pointer ke suatu fungsi. Misalnya, bandingkan

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

dengan

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

Namun, orang dapat berargumen bahwa keterbacaan yang lebih baik dapat dicapai hanya dengan memperkenalkan alias tipe untuk penunjuk fungsi:

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

10

Lihat artikel bagus ini: http://www.cprogramming.com/c++11/c++11-auto-decltype-return-value-after-function.html Contoh yang sangat bagus ketika menggunakan sintaks ini tanpa deklarasi dalam permainan :

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;
}

Dan penjelasan brilian juga dicuri dari artikel Alex Allain "Karena nilai kembalian berada di akhir fungsi, bukan sebelumnya, Anda tidak perlu menambahkan cakupan kelas."

Bandingkan dengan kemungkinan kasus ini ketika seseorang secara tidak sengaja melupakan ruang lingkup kelas, dan, untuk bencana yang lebih besar, PersonType lain didefinisikan dalam cakupan global:

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

7
Saya tidak yakin ini termasuk dalam kategori "bencana": jika jenisnya salah, kode tidak akan dapat dikompilasi. Kesalahan runtime dapat memiliki konsekuensi yang menghancurkan; kesalahan waktu kompilasi, tidak terlalu banyak.
James McNellis

4
@JamesMcNellis membandingkan keluaran kompilator: prog.cpp:13:12: error: prototype for 'PersonType Person::getPersonType()' does not match any in class 'Person'vs. prog.cpp:13:1: error: 'PersonType' does not name a type Kesalahan pertama dari kompilator adalah, setidaknya bagi saya, lebih buruk untuk dipahami.
PiotrNycz

Secara pribadi saya tidak setuju, saya menemukan pesan kedua lebih sulit untuk dibaca, dan saya lebih suka implementasinya terlihat seperti deklarasi.
jrh
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.