TL; DR
Ekstra parantezler, aşağıdaki bağlamlarda bir C ++ programının anlamını değiştirir:
- bağımsız değişkene bağlı ad aramasını önleme
- liste bağlamlarında virgül operatörünü etkinleştirme
- sinir bozucu çözümlemelerin belirsizlik çözümü
decltype
İfadelerde referanslığın çıkarılması
- önişlemci makro hatalarını önleme
Bağımsız değişkene bağlı ad aramasını önleme
Standart Ek A'da ayrıntılı olarak açıklandığı gibi, post-fix expression
formun (expression)
a biçimi a'dır primary expression
, ancak bir değildir id-expression
ve bu nedenle bir değildir unqualified-id
. Bu (fun)(arg)
, geleneksel forma kıyasla formun işlev çağrılarında bağımsız değişkene bağlı ad aramasının önlendiği anlamına gelir fun(arg)
.
3.4.2 Bağımsız değişkene bağlı ad araması [basic.lookup.argdep]
1 Bir işlev çağrısındaki (5.2.2) sonek ifadesi niteliksiz bir kimlik olduğunda , olağan niteliksiz arama (3.4.1) sırasında dikkate alınmayan diğer ad alanları aranabilir ve bu ad alanlarında, ad alanı-kapsam arkadaş işlevi veya Aksi halde görünmeyen işlev şablonu bildirimleri (11.3) bulunabilir. Aramadaki bu değişiklikler, bağımsız değişkenlerin türlerine (ve şablon şablon bağımsız değişkenleri için, şablon bağımsız değişkeninin ad alanına) bağlıdır. [ Misal:
namespace N {
struct S { };
void f(S);
}
void g() {
N::S s;
f(s);
(f)(s);
}
—Son örnek]
Virgül operatörünü liste bağlamlarında etkinleştirme
Virgül operatörü, çoğu liste benzeri bağlamda (işlev ve şablon bağımsız değişkenleri, başlatıcı listeleri vb.) Özel bir anlama sahiptir. Bu a, (b, c), d
tür bağlamlarda formun parantezleri , normal forma kıyasla virgül operatörünü etkinleştirebilira, b, c, d
parantezleri, virgül operatörünün uygulanmadığı .
5.18 Virgül operatörü [expr.comma]
2 Virgülün özel bir anlamın verildiği bağlamlarda, [Örnek: işlevler için bağımsız değişkenler listelerinde (5.2.2) ve başlatıcı listelerinde (8.5) - son örnek] Madde 5'te açıklandığı gibi virgül operatörü yalnızca parantez içinde görünebilir. [ Misal:
f(a, (t=3, t+2), c);
ikincisi 5 değerine sahip üç bağımsız değişkeni vardır - son örnek]
Sinir bozucu ayrıştırmaların belirsizlik çözünürlüğü
C ve onun gizli işlev bildirimi sözdizimi ile geriye dönük uyumluluk, can sıkıcı ayrıştırmalar olarak bilinen şaşırtıcı ayrıştırma belirsizliklerine yol açabilir. Esasen, bildirim olarak ayrıştırılabilen her şey tek bir bildirim olarak çözümlenecektir. rakip ayrıştırma da geçerli olsa bile .
6.8 Belirsizlik çözümü [stmt.ambig]
1 İfade ifadeleri ve bildirimleri içeren dilbilgisinde bir belirsizlik vardır : En soldaki alt ifadesi, işlev tarzı açık tür dönüşümü (5.2.3) olan bir ifade-ifadesi, ilk açıklamanın bir ( . bu durumlarda ifadesi bir beyanıdır .
8.2 Belirsizlik çözümü [dcl.ambig.res]
1 6.8'de belirtilen bir fonksiyon tarzı atama ile bir bildirim arasındaki benzerlikten kaynaklanan belirsizlik, bir bildirim bağlamında da ortaya çıkabilir . Bu bağlamda, seçim, bir parametre adı etrafında yedekli bir parantez kümesi içeren bir işlev bildirimi ile başlatıcı olarak bir işlev tarzı döküm içeren bir nesne bildirimi arasındadır. 6.8'de belirtilen belirsizlikler için olduğu gibi, karar, muhtemelen bir beyan olabilecek herhangi bir yapıyı bir beyan olarak değerlendirmektir . [Not: Bir bildirimin belirsizliği, işlev olmayan bir tür atama ile, başlatmayı belirtmek için an = ile veya parametre adının etrafındaki gereksiz parantezler kaldırılarak açıkça kaldırılabilir. —End note] [Örnek:
struct S {
S(int);
};
void foo(double a) {
S w(int(a));
S x(int());
S y((int)a);
S z = int(a);
}
—Son örnek]
Bunun ünlü bir örneği, Etkili STL kitabının 6. maddesinde Scott Meyers tarafından popüler hale getirilen En Vexing Ayrıştırmadır :
ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile),
istream_iterator<int>());
Bu data
, dönüş türü olan bir işlevi bildirir list<int>
. İşlev verileri iki parametre alır:
- İlk parametre adlandırılır
dataFile
. Tipidir istream_iterator<int>
. Etrafındaki parantezler dataFile
gereksizdir ve dikkate alınmaz.
- İkinci parametrenin adı yoktur. Türü, hiçbir şey almayan ve bir
istream_iterator<int>
.
İlk fonksiyon argümanının etrafına fazladan parantez koymak (ikinci argümanın etrafına parantezler geçersizdir) belirsizliği çözecektir
list<int> data((istream_iterator<int>(dataFile)),
istream_iterator<int>());
C ++ 11, birçok bağlamda bu tür çözümleme sorunlarını yan adımlara atmaya izin veren küme ayracı başlatıcı sözdizimine sahiptir.
Referanslık çıkarılması decltype
ifadeler
auto
Tür kesintisinin aksine decltype
, referanslığın (ldeğer ve rdeğer referansları) çıkarılmasına izin verir. Kurallar decltype(e)
ve decltype((e))
ifadeleri birbirinden ayırır :
7.1.6.2 Basit tür belirticiler [dcl.type.simple]
4 Bir ifade için e
, ile gösterilen türdecltype(e)
aşağıdaki gibi tanımlanır:
- e
parantezsiz bir id ifadesi veya parantezsiz bir sınıf üyesi erişimiyse (5.2.5), decltype(e)
tarafından adlandırılan varlığın türüdür e
. Böyle bir varlık yoksa veya e
bir dizi aşırı yüklenmiş işlevi adlandırırsa, program bozuktur;
- aksi takdirde, eğer e
bir xvalue ise, decltype(e)
is T&&
, nerede T
türü e
;
- aksi takdirde, e
bir lvalue olduğu, decltype(e)
olduğu T&
, burada T
türüdüre
;
- aksi takdirde, decltype(e)
türüdür e
.
Decltype tanımlayıcısının işleneni, değerlendirilmemiş bir işlenendir (Madde 5). [ Misal:
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = 0;
decltype(i) x2;
decltype(a->x) x3;
decltype((a->x)) x4 = x3;
—Son örneği] [Not: decltype(auto)
İçerdiği türleri belirleme kuralları
7.1.6.4'te belirtilmiştir. - notu gönder]
Kuralları decltype(auto)
, başlatan ifadenin RHS'sindeki ekstra parantezler için benzer bir anlama sahiptir. İşte C ++ SSS'den bir örnek ve bu ilgili Soru-Cevap
decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }
decltype(auto) look_up_a_string_2() { auto str = lookup1(); return(str); }
İlk sonuç, yerel değişkene referans olan string
ikinci döner .string &
str
Önişlemci makroyla ilgili hataları önleme
En yaygın olanları aşağıda listelenen uygun C ++ diliyle etkileşimlerinde önişlemci makroları olan bir dizi incelik vardır.
#define TIMES(A, B) (A) * (B);
İstenmeyen operatör önceliğinden kaçınmak için makro tanımının içindeki makro parametreleri etrafında parantezler kullanmak (örneğin, TIMES(1 + 2, 2 + 1)
burada 9 verir, ancak parantezler (A)
ve(B)
- İçinde virgül bulunan makro bağımsız değişkenlerin etrafına parantez kullanarak
assert((std::is_same<int, int>::value));
aksi takdirde derlenmez
- Dahil edilen başlıklarda makro genişletmeye karşı koruma sağlamak için bir işlevin etrafında parantezler kullanma:
(min)(a, b)
(ADL'yi devre dışı bırakmanın istenmeyen yan etkisiyle)
&(C::f)
işleneni&
hala olurC::f
, değil mi?