Pertanyaan Bagaimana cara otomatis menyimpulkan jenis?


Saya memiliki beberapa kasus penggunaan auto:

auto s = expr;          //s is always lvalue
auto & s = expr;        //s is always lvalue reference? What if expr is rvalue?
auto && s = expr;       //s is perfectly forwarded

Apakah mereka benar? Jika tidak, mengapa?


4
2018-01-12 01:03


asal


Jawaban:


DIP benar dan saya ingin menguraikannya.

Pertama-tama, kesimpulannya adalah dari dyp:

Jenis disimpulkan untuk auto dalam deklarasi variabel didefinisikan   melalui aturan deduksi argumen template, lihat [dcl.spec.auto] / 6;   dengan satu pengecualian: jika penginisialisasi adalah braced-init-list, the   tipe disimpulkan adalah a std::initializer_list.

Saya akan menjelaskan.

Pertama,

auto s = expr;

Ini sama dengan menyimpulkan T dari expr,

template<class T>
void f(T s);

f(expr);

Aturan untuk deduksi argumen template cukup rumit, karena Anda hanya peduli dengan nilai dan nilai-nilai, mari fokus pada ini.

Pengurangan argumen template adalah dengan membandingkan jenis parameter template (sebut saja P, pada kasus ini P aku s T), dan argumen yang sesuai (sebut saja A, dalam hal ini, jenis expr).

Dari 14.8.2.1,

Jika P bukan tipe referensi:

- Jika A adalah tipe array, jenis pointer yang dihasilkan oleh konversi standar array-to-pointer (4.2) adalah   digunakan sebagai pengganti A untuk deduksi tipe; jika tidak,

- Jika A adalah tipe fungsi, jenis penunjuk yang dihasilkan oleh konversi standar fungsi-ke-penunjuk (4.3)   digunakan sebagai pengganti A untuk deduksi tipe; jika tidak,

- Jika A adalah tipe berkualifikasi-CV, kualifikasi tingkat atas dari tipe A diabaikan untuk deduksi jenis.

Jadi jika expr adalah array atau fungsi, itu akan diperlakukan sebagai pointer, jika expr memiliki cv-kualifikasi (const dll), mereka akan diabaikan.

Jika P adalah tipe berkualifikasi-cv, cv-kualifier tingkat atas dari PJenis diabaikan untuk deduksi jenis.

Ini sebenarnya mengatakan:

const auto s = expr;

s adalah const variabel, tetapi untuk deduksi tipe untuk auto tujuan, const akan dihapus.

Jadi, dari aturan di atas, auto akan disimpulkan untuk jenis expr (setelah beberapa jenis konversi yang disebutkan di atas).

Perhatikan bahwa, ketika ekspresi adalah referensi T, itu akan disesuaikan T sebelum analisis sebelumnya.

Terserah expr adalah - rvalue, lvalue, atau lvalue / rvalue ref type - tipe auto akan selalu menjadi tipe expr tanpa referensi.

auto s1 = 1; //int
int &x = s1;
auto s2 = x; //int
int &&y = 2;
auto s3 = y; //int

Kedua, mari kita lihat

auto &s = expr;

Ini akan sama dengan

template<class T>
void f(T &s);

f(expr);

Aturan tambahan dari standar adalah sebagai berikut:

Jika P adalah tipe referensi, jenis yang disebut oleh P digunakan untuk deduksi tipe.

Jadi, pengurangan otomatis akan sama persis dengan tanpa &, tetapi setelah auto jenis dikurangkan, & ditambahkan ke akhir auto.

//auto &s1 = 1; //auto is deducted to int, int &s1 = 1, error!
const auto &s1 = 1; //auto is deducted to int, const int &s1 = 1; ok!
const int &x = s1;
auto &s2 = x; //auto is int, int &s2 = x; ok!
int &&y = 2;
auto &s3 = y; //auto is int, int &s3 = y; ok! 

Perhatikan bahwa yang terakhir y adalah lvalue. Aturan C ++ adalah: referensi rvalue bernama adalah lvalue.

Akhirnya:

auto &&s = expr;

Ini tidak diragukan sama dengan

template<class T>
void f(T &&s);

f(expr);

Satu aturan tambahan dari standar:

Jika P adalah rvalue referensi ke parameter template yang tidak memenuhi syarat cv dan   argumennya adalah lvalue, tipe "referensi nilai ke A" digunakan dalam   tempat Auntuk deduksi tipe.

Ini sebenarnya mengatakan itu, jika expr adalah rvalue, aturannya akan sama dengan kasus kedua (kasus lvalue), tetapi jika expr adalah lvalue, jenis A akan menjadi referensi lnilai untuk A.

Catatan dari penjelasan sebelumnya, A tidak pernah referensi, karena jenis ekspresi tidak pernah menjadi referensi. Tetapi untuk kasus khusus ini (auto &&, dan A adalah lvalue), referensi ke A harus digunakan, terlepas expr sendiri adalah tipe referensi atau bukan.

Contoh:

auto &&s1 = 1; //auto is deducted to int, int &&s1 = 1, ok!
int x = 1;
auto &&s2 = x; //x is lvalue, so A is int &, auto is deducted to int &, int & &&s2 = x; ok!
int &&y = 2;
auto &&s3 = y; //y is lvalue, auto is int &, int & &&s3 = y; ok!

5
2018-01-12 03:32



Karena tidak ada yang memberikan jawaban dan saya agak mengerti sekarang (terima kasih kepada @dyp), saya hanya akan memposting jawaban sendiri. Tunjukkan kesalahan jika ada:

auto s = expr;

Jika expr adalah lvalue, prvalue, atau referensi apa pun, s selalu bernilai dan salinan dibuat.

auto& s = expr;

Jika expr adalah lvalue, referensi nilai atau rujukan referensi, s adalah referensi lnilai. Jika expr adalah prvalue, itu adalah kesalahan dan tidak legal.

auto&& s = expr;

s sempurna diteruskan (rvalue akan menjadi rujukan referensi dan runtuh).


0
2018-01-12 02:09