Apakah ini konstruktor gaya C ++ lama?

17

Di sini sepotong kode C ++.

Dalam contoh ini, banyak blok kode terlihat seperti panggilan konstruktor. Sayangnya, kode blok 3 tidak (Anda dapat memeriksanya menggunakan https://godbolt.org/z/q3rsxn dan https://cppinsights.io ).

Saya pikir, ini adalah notasi C ++ lama dan bisa menjelaskan pengenalan notasi konstruksi C ++ 11 baru menggunakan {} (cf # 4).

Apakah Anda memiliki penjelasan untuk T(i)makna, sangat dekat dengan notasi konstruktor, tetapi jelas sangat berbeda?

struct T {
   T() { }
   T(int i) { }
};

int main() {
  int i = 42;
  {  // #1
     T t(i);     // new T named t using int ctor
  }
  {  // #2
     T t = T(i); // new T named t using int ctor
  }
  {  // #3
     T(i);       // new T named i using default ctor
  }
  {  // #4
     T{i};       // new T using int ctor (unnamed result)
  }
  {  // #5
     T(2);       // new T using int ctor (unnamed result)
  }
}

NB: dengan demikian, T(i)(# 3) setara dengan T i = T();

Pascal H.
sumber
1
Saya pikir semua pernyataan Anda benar.
Arne J
Perhatikan bahwa kompiler akan memberi tahu Anda semua yang perlu Anda ketahui jika Anda hanya bertanya: Tambahkan -Walldan Anda mendapat " warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'i' [-Wvexing-parse]" dari dentang, atau " warning: unnecessary parentheses in declaration of 'i' [-Wparentheses]" yang sedikit kurang termotivasi dari gcc .
Max Langhof
@ QuentinUK terima kasih atas tautan ini. Saya tahu tentang fungsi (misalnya T t()) tetapi tidak untuk ekspresi deklarasi yang begitu sederhana. Yang pasti, ini bisa menjengkelkan .
Pascal H.

Jawaban:

17

Pernyataan:

T(i);

setara dengan:

T i;

Dengan kata lain, itu mendeklarasikan variabel bernama idengan tipe T. Ini karena tanda kurung diperbolehkan dalam deklarasi di beberapa tempat (untuk mengubah pengikatan deklarator) dan karena pernyataan ini dapat diuraikan sebagai deklarasi, itu adalah deklarasi (meskipun mungkin lebih masuk akal sebagai ekspresi).

Brian
sumber
Jadi, apakah ini hanya pilihan interpretasi yang diwarisi dari spesifikasi C di mana int(i)juga menyatakan intnama i?
Pascal H.
@ Pascal Dari sudut pandang tertentu, itu mungkin benar. Stroustrup menulis dalam D&E bahwa ia telah mempertimbangkan alternatif, sintaksis deklarasi yang lebih intuitif untuk C ++. Jika C ++ tidak harus kompatibel dengan C, maka mungkin itu akan memiliki sintaks alternatif, dan dengan demikian menghindari potensi ambiguitas dengan ekspresi.
Brian
-1

Anda dapat menggunakan Compiler Explorer untuk melihat apa yang terjadi di assembler.

Anda dapat melihat bahwa # 1, # 2 # 4 dan # 5 melakukan hal yang sama tetapi anehnya # 3 memanggil konstruktor lain (konstruktor objek dasar).

Adakah yang punya penjelasan?

Kode assembler:

::T() [base object constructor]:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        nop
        pop     rbp
        ret
T::T(int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 42
// #1
        mov     edx, DWORD PTR [rbp-4]
        lea     rax, [rbp-7]
        mov     esi, edx
        mov     rdi, rax
        call    T::T(int)
// #2
        mov     edx, DWORD PTR [rbp-4]
        lea     rax, [rbp-8]
        mov     esi, edx
        mov     rdi, rax
        call    T::T(int)
// #3
        lea     rax, [rbp-9]
        mov     rdi, rax
        call    T::T() [complete object constructor]
// #4
        mov     edx, DWORD PTR [rbp-4]
        lea     rax, [rbp-6]
        mov     esi, edx
        mov     rdi, rax
        call    T::T(int)
// #5
        lea     rax, [rbp-5]
        mov     esi, 2
        mov     rdi, rax
        call    T::T(int)

        mov     eax, 0
        leave
        ret
Matthieu H
sumber