Tanda kurung dalam C ++ digunakan di banyak tempat: misalnya dalam pemanggilan fungsi dan ekspresi pengelompokan untuk mengesampingkan prioritas operator. Terlepas dari tanda kurung tambahan ilegal (seperti di sekitar daftar argumen panggilan fungsi), aturan umum -tetapi tidak mutlak- dari C ++ adalah bahwa tanda kurung tambahan tidak pernah merugikan :
5.1 Ekspresi utama [expr.prim]
5.1.1 Umum [expr.prim.general]
6 Ekspresi dalam kurung adalah ekspresi primer yang jenis dan nilainya identik dengan ekspresi tertutup. Adanya tanda kurung tidak mempengaruhi apakah ekspresi tersebut adalah nilai l. Ekspresi dalam tanda kurung dapat digunakan dalam konteks yang sama persis dengan yang di mana ekspresi tertutup dapat digunakan, dan dengan arti yang sama, kecuali ditunjukkan lain .
Pertanyaan : dalam konteks apa tanda kurung ekstra mengubah arti program C ++, selain mengesampingkan prioritas operator dasar?
CATATAN : Saya menganggap pembatasan sintaks pointer-ke-anggota&qualified-id
tanpa tanda kurung berada di luar ruang lingkup karena membatasi sintaks daripada mengizinkan dua sintaks dengan arti yang berbeda. Demikian pula, penggunaan tanda kurung di dalam definisi makro preprocessor juga melindungi dari prioritas operator yang tidak diinginkan.
sumber
&(C::f)
, operan dari&
masihC::f
, bukan?expr.unary.op/4
: Sebuah pointer ke anggota hanya dibentuk ketika sebuah eksplisit&
digunakan dan operannya adalah id-yang memenuhi syarat yang tidak diapit tanda kurung.()
atas pemilih pointer-ke-anggota::*
Jawaban:
TL; DR
Tanda kurung tambahan mengubah arti program C ++ dalam konteks berikut:
decltype
ekspresiMencegah pencarian nama yang bergantung pada argumen
Seperti yang dijelaskan dalam Lampiran A Standar,
post-fix expression
bentuk(expression)
a adalah aprimary expression
, tetapi bukan anid-expression
, dan oleh karena itu bukan anunqualified-id
. Ini berarti bahwa pencarian nama yang bergantung pada argumen dicegah dalam pemanggilan fungsi dari formulir(fun)(arg)
dibandingkan dengan formulir konvensionalfun(arg)
.3.4.2 Pencarian nama yang bergantung pada argumen [basic.lookup.argdep]
namespace N { struct S { }; void f(S); } void g() { N::S s; f(s); // OK: calls N::f (f)(s); // error: N::f not considered; parentheses // prevent argument-dependent lookup }
Mengaktifkan operator koma dalam konteks daftar
Operator koma memiliki arti khusus di sebagian besar konteks seperti daftar (argumen fungsi dan templat, daftar penginisialisasi, dll.). Tanda kurung formulir
a, (b, c), d
dalam konteks seperti itu dapat mengaktifkan operator koma dibandingkan dengan formulir biasa dia, b, c, d
mana operator koma tidak berlaku.5.18 Operator koma [expr.comma]
f(a, (t=3, t+2), c);
Resolusi ambiguitas dari parsing yang mengganggu
Kompatibilitas mundur dengan C dan sintaks deklarasi fungsi rahasia dapat menyebabkan ambiguitas penguraian yang mengejutkan, yang dikenal sebagai penguraian menjengkelkan. Pada dasarnya, apa pun yang dapat diuraikan sebagai deklarasi akan diuraikan sebagai satu deklarasi , meskipun parse yang bersaing juga akan diterapkan.
6.8 Resolusi ambiguitas [stmt.ambig]
8.2 Resolusi ambiguitas [dcl.ambig.res]
struct S { S(int); }; void foo(double a) { S w(int(a)); // function declaration S x(int()); // function declaration S y((int)a); // object declaration S z = int(a); // object declaration }
Contoh terkenal dari ini adalah Most Vexing Parse , nama yang dipopulerkan oleh Scott Meyers di Item 6 dari buku Effective STL-nya :
ifstream dataFile("ints.dat"); list<int> data(istream_iterator<int>(dataFile), // warning! this doesn't do istream_iterator<int>()); // what you think it does
Ini mendeklarasikan sebuah fungsi
data
, yang tipe kembaliannya adalahlist<int>
. Data fungsi mengambil dua parameter:dataFile
. Jenisnya adalahistream_iterator<int>
. Tanda kurung di sekitarnyadataFile
tidak berguna dan diabaikan.istream_iterator<int>
.Menempatkan tanda kurung tambahan di sekitar argumen fungsi pertama (tanda kurung di sekitar argumen kedua adalah ilegal) akan menyelesaikan ambiguitas
list<int> data((istream_iterator<int>(dataFile)), // note new parens istream_iterator<int>()); // around first argument // to list's constructor
C ++ 11 memiliki sintaks brace-initializer yang memungkinkan untuk mengesampingkan masalah penguraian seperti itu dalam banyak konteks.
Mengurangi referensi dalam
decltype
ekspresiBerbeda dengan
auto
deduksi tipe,decltype
memungkinkan referensi (referensi nilai l dan nilai r) untuk disimpulkan. Aturan membedakan antaradecltype(e)
dandecltype((e))
ekspresi:7.1.6.2 Penentu tipe sederhana [dcl.type.simple]
const int&& foo(); int i; struct A { double x; }; const A* a = new A(); decltype(foo()) x1 = 0; // type is const int&& decltype(i) x2; // type is int decltype(a->x) x3; // type is double decltype((a->x)) x4 = x3; // type is const double&
Aturan untuk
decltype(auto)
memiliki arti yang sama untuk tanda kurung tambahan di kanan atas ekspresi inisialisasi. Berikut adalah contoh dari C ++ FAQ dan Q&A terkait inidecltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; } //A decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); } //B
Pengembalian pertama
string
, pengembalian keduastring &
, yang merupakan referensi ke variabel lokalstr
.Mencegah kesalahan terkait makro praprosesor
Ada sejumlah kehalusan dengan makro praprosesor dalam interaksinya dengan bahasa C ++ yang sesuai, yang paling umum tercantum di bawah ini
#define TIMES(A, B) (A) * (B);
untuk menghindari prioritas operator yang tidak diinginkan (misalnya diTIMES(1 + 2, 2 + 1)
mana menghasilkan 9 tetapi akan menghasilkan 6 tanpa tanda kurung di sekitarnya(A)
dan(B)
assert((std::is_same<int, int>::value));
yang tidak dapat dikompilasi(min)(a, b)
(dengan efek samping yang tidak diinginkan juga menonaktifkan ADL)sumber
if
/while
jika ekspresi adalah tugas. Misalnyaif (a = b)
- peringatan (maksud Anda==
?), Sementaraif ((a = b))
- tidak ada peringatan.(min)(a, b)
(dengan MACRO jahatmin(A, B)
) adalah bagian dari pencegahan pencarian nama yang bergantung pada argumen?Secara umum, dalam bahasa pemrograman, tanda kurung "ekstra" menyiratkan bahwa mereka tidak mengubah urutan atau makna penguraian sintaksis. Mereka ditambahkan untuk memperjelas urutan (prioritas operator) untuk kepentingan orang-orang yang membaca kode, dan satu-satunya efek mereka adalah sedikit memperlambat proses kompilasi, dan mengurangi kesalahan manusia dalam memahami kode (mungkin mempercepat proses pengembangan secara keseluruhan ).
Jika sekumpulan tanda kurung benar-benar mengubah cara ekspresi diuraikan, maka menurut definisi tidak tambahan. Tanda kurung yang mengubah penguraian ilegal / tidak valid menjadi penguraian legal bukanlah "ekstra", meskipun itu mungkin menunjukkan desain bahasa yang buruk.
sumber