2016-03-01 30 views
34

Aşağıdaki kod GCC ile temiz bir şekilde derler:Yenisini bildirmek için önceki işlev parametresini kullanmak yasal mıdır?

void func(int arg1, decltype(arg1) arg2) 
{ 
    (void)arg2; 
} 
int main(){} 

ben derlemek için bu komutu kullanılır:

g++ -std=c++14 test.cpp -o test -pedantic-errors -Wall -Wextra 

Ama işlev bildiriminde ortasında bir parametrenin böyle kullanım garip görünüyor. Aslında standart C++ 'da geçerli mi, yoksa GCC uzantısı mı? Biz N3979 bakarsanız

+0

Ben arg1' 'tipi çok daha karmaşık gerçek kodda olduğunu varsayalım? Spesifikasyona ya da herhangi bir referansa bakmadan, ama ayrıştırma hakkında biraz bilgi sahibi olursam, sanırım tamamdır, çünkü C++ gibi dilleri ayrıştırmak çoktan soldan sağa bir ilişkidir. Derleyici 'arg2' için bildirimi ayrıştırdığında, zaten 'arg1' bildirimini çözümlemiş olmalı, bu nedenle arg1 türünü kesinlikle bilmelidir. Eğer gerçekten "izinli" ise, bilmiyorum, ikisi de ters yönde çalışacaksa ('arg1' için 'decltype (arg2)' yi kullanarak). –

+0

@JoachimPileborg elbette, gerçek kod 'arg1' için çok daha karmaşık bir türe sahiptir, aksi takdirde üzerinde 'decltype' kullanmayı denemeyi düşünürdüm. – Ruslan

+0

FWIW, MSVC++ 2013 ve onun Intellisense (EDG) her ikisi de bunu kabul eder. – MSalters

cevap

20

Bu sorun değil. ISO C++11 Standard bile durumunuzu bir örnek olarak verir.

İlk parametre alanı içinde:

3.3.3 Blok kapsamı [ basic.scope.(Lambda-Bildiricisi görünen da dahil olmak üzere) ya da bir fonksiyonu tanım (8.4) bir fonksiyonu yerel önceden belirlenmiş değişken başlar ]

bir işlev parametre adı potansiyel kapsamı yerel onun beyan noktası.

bir örnek

burada bulunabilir:

8.3.5 fonksiyonları [dcl.fct]

[ Not: Bu dönüşümü yapar parametrelerin türlerini etkilemez. Örneğin int (*) (const int p, decltype (p) *) ve int (*) (int, const int *) aynı türlerdir. - uç not ]

+0

Bir bağlantı var mı? 321 –

+3

@AaronHall "C++ 11" Standaard burada satılmaktadır: http://webstore.ansi.org/RecordDetail.aspx?sku=INCITS%2FISO%2FIEC+14882-2012 ancak yapabilirsiniz "n3290.pdf" için googling ile ücretsiz bir taslak olsun (hemen hemen aynı). Finallere kadar (ancak dahil değil) tüm taslaklar ücretsizdir. – Galik

6

[dcl.fct.default] biz

Standart argümanlar fonksiyonu her çağrıldığında değerlendirilir var. Fonksiyon argümanlarının değerlendirme sırası belirtilmemiş. Sonuç olarak, bir fonksiyonun parametreleri, değerlendirilmese bile, bir varsayılan argümanda kullanılmamalıdır. Varsayılan argümandan önce bildirilen bir işlevin parametreleri kapsam dahilindedir ve ad alanı ile sınıf üyesi adları gizlenebilir. [Örnek:

int a; 
int f(int a, int b = a);    // error: parameter a 
             // used as default argument 
typedef int I; 
int g(float I, int b = I(2));   // error: parameter I found 
int h(int a, int b = sizeof(a));  // error, parameter a used 
             // in default argument 

[...]

Vurgu mayın örnek a yılında

yüzden b vardığımızda bilinen ve çağıran kapsamından a gizler edilir . Bu, her bir fonksiyon parametresinin, her bir sonraki parametreden önce bilindiğine inanmamı sağlar. Bu, türünü kullanabilmeniz gerektiği anlamına gelir. Değerini kullanamazsınız - değerlerin değerlendirilme sırası belirtilmemiş - ancak isimler soldan sağa doğru sırayla yapılmalıdır.

+0

Kesinlikle kapsamdalar ama bu yeterli mi? – MSalters

+0

@MSalters bunları "decltype" ile kullanmak için öyle düşünüyorum. – NathanOliver

10

Evet, bu yasal. Temel olarak sadece bir kapsam sorunu. [Basic.scope.block] kaynaktan:

bir işlev parametre adı potansiyel kapsamı veya bir fonksiyon tanımındaki bir işlev yerel önceden belirlenmiş bir değişkenin (8.4), (a lambda Bildiricisi görünen de dahil) beyan noktasında başlar.

arg1 kapsamı burada başlar:

void func(int arg1, decltype(arg1) arg2) 
------------------^ 

Dolayısıyla arg1 arg2 beyanında kapsamı içindedir. Bence bu yeterli.

arg1 için arg2 varsaymak izin vermeme kural ayrıdır - Bana arg1 kapsamında ve açıkça izin verilmeyen gerektiğini düşündürür.

İlgili konular