2013-04-06 21 views
20

Bu GCC ve Clang ile başarısız Benim için sürpriz bu koduDerleyici, "A (A &)" ifadesinin bir an için rimini kabul ettiğini düşünüyor?

struct A { A(); A(A&); }; 
struct B { B(const A&); }; 

void f(A); 
void f(B); 

int main() { 
    f(A()); 
} 

var. Clang ikinci f çalışıyor iken

Compilation finished with errors: 
source.cpp:8:10: error: no matching constructor for initialization of 'A' 
     f(A()); 
     ^~~ 
source.cpp:1:21: note: candidate constructor not viable: expects an l-value for 1st argument 
    struct A { A(); A(A&); }; 
        ^
source.cpp:1:16: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 
    struct A { A(); A(A&); }; 
      ^
source.cpp:4:13: note: passing argument to parameter here 
    void f(A); 

Neden ilk f seçerim örneğin diyor? İlk f'u kaldırırsam, çağrı başarılı olur. Ne ayracı başlatma kullanırsanız, o da

int main() { 
    f({A()}); 
} 

Hepsi ikinci f çağrı çalışıyor, benim için daha garip.

cevap

17

Bu bir dil quirk. İlk f, A numaranız argüman türü (A) ile eşleşmesi gerekmediğinden daha iyi eşleşir, ancak derleyici çağrıyı uygun kopya kurucusunun bulunamayacağı gerçeği aramanın başarısız olmasına neden olur. Dil, aşırı yük çözme adımı gerçekleştirilirken gerçek aramanın fizibilitesinin dikkate alınmasına izin vermez.

yakın uygun standart Gönder ISO/IEC 14.882 2011 hakkında 13.3.3.1.2 Kullanıcı tanımlı dönüşüm sekansları [over.ics.user]:

aynı sınıfa sınıfı türü bir ifadenin bir dönüşüm türü Tam Eşleşme sıralaması verilir ve bir kopyalama/taşıma yapıcısı (ör., kullanıcı tanımlı bir dönüşüm işlevi) gerçeğine rağmen, bu tür bir taban sınıfına sınıf türünün bir ifadesinin dönüşümüne Dönüşüm sırası verilir.) bu davalar için çağrılır. Liste başlatma durum için

, muhtemelen bakmak gerekir: 13.3.3.1.2 Kullanıcı tanımlı dönüşüm dizileri [over.ics.user]

zaman olmayan agrega sınıfının nesneleri T listesi-başlatılmış olan tip (8.5.4), aşırı yük çözünürlük iki fazda kurucu seçer:

- İlk olarak, aday fonksiyonları sınıf T başlatıcı listesi kurucular (8.5.4) ve olan argüman listesi bir şarkı olarak başlatıcı listesinden oluşur le argüman.

- hayır canlı başlatıcı listesi yapıcısı bulunursa, aşırı yük çözünürlük aday fonksiyonları tüm sınıf T kurucular ve argüman listesi elemanlarının başlatıcı listenin oluşur nerede, yeniden gerçekleştirilir.

aşırı yük çözünürlük f(A) ve f(B) için her durumda geçerli Müteahhitler bakmak zorundadır Çünkü istifi A()A(A&) ama B(const A&) hala canlı olması bağlamaya çalışırken reddetmek zorundadır.

+0

Teşekkürler! “{...}” davası için böyle bir kural bulamıyorum. Bu, '{...}' durumunun neden işe yaradığını açıklıyor mu? –

+0

@ JohannesSchaub-litb: Emin değilim, tbh, işlevi bir _braced-init-list_ ile çağırıyorsunuz, bu yüzden kurallar kesinlikle farklı. –

+0

@ JohannesSchaub-litb Bkz. [Over.ics.list]. Sanırım bu konuyla ilgili.ref]/3 (kodunuzu daha önce yanlış okuyorum): Canlı işlevlerin alt kümesini oluştururken, “A (A &)” ifadesi, bir const olmayan lvalue referansına geçici olarak bağlandığı için geçerli kabul edilmez. – dyp