2013-06-08 28 views
8
#include <iostream> 
using namespace std; 
class Myclass{ 
     private: 
       int i; 
     public: 
       template<typename U>Myclass(U& lvalue):i(lvalue){cout<<i <<" template light reference" <<endl;i++;} 
       //Myclass(Myclass &lvalue):i(lvalue){cout<<i <<" light reference" <<endl;i++;} 
       template<typename U>Myclass(U&& rvalue):i(rvalue){cout<<i <<" template right reference" <<endl;i++;} 
}; 

int main(int argc,char*argv[]) 
{ 
Myclass a(0); 
Myclass b(a); 
Myclass c(2); 
return 0; 
} 

hata iletisi: sırayla derleyici zorundadır bu yapıcı görüşmeNeden T & & T && kopya yapıcılarım belirsiz?

Myclass b(a); 

çözmek için: Yani burada

rightvalue.cpp: In function ‘int main(int, char**)’: 
rightvalue.cpp:15:12: error: call of overloaded ‘Myclass(Myclass&)’ is ambiguous 
rightvalue.cpp:15:12: note: candidates are: 
rightvalue.cpp:10:23: note: Myclass::Myclass(U&&) [with U = Myclass&] 
rightvalue.cpp:8:23: note: Myclass::Myclass(U&) [with U = Myclass] 
rightvalue.cpp:4:7: note: constexpr Myclass::Myclass(const Myclass&) 
rightvalue.cpp:4:7: note: constexpr Myclass::Myclass(Myclass&&) <near match> 
rightvalue.cpp:4:7: note: no known conversion for argument 1 from ‘Myclass’ to ‘Myclass&&’ 
+5

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57172 –

+0

@MarkTolonen 'const' olarak değiştiriliyor U & 'sonuçların çıktı 'template right reference' – yuan

+0

çıktısı Hata 4.9 için düzeltildi, ücretsiz onunla oynamak ve yeni davranışla bulduğunuz sorunları bildirmek. –

cevap

9

olur (ya da daha doğrusu, gerçekleşebilir) nedir Aşırı yük çözünürlüğü uygulayın ve ilk olarak hangi kurucuların uygun adaylar olduğuna karar verin.

fark ilk şey her iki kurucular yaşayabilir olmasıdır: T&& gibi formlar daima rvalue başvuruları içine gidermezsedo (ne geçiyoruz bir rvalue ise sadece durum). Scott Meyers'ın "universal references" numaralı telefonunda yaptığı budur (bu terimin standart olmadığını not edin).

derleyici ikinci yapıcı yaşayabilir olup olmadığını görmek için tip kesinti gerçekleştirmeye çalışır

, bu durumda tip TMyclass& olmak çıkarılabilir olacak - ne geçiyoruz (a) bir lvalue olduğundan; ve referans daraltma kuralları nedeniyle, Myclass& &&, Myclass& değerini verir, böylece ilk kurucunuzun sahip olduğu aynı imzaya sahip olursunuz.

Arama da belirsiz mi? Marc Glisse in the comments to the question ve Jonathan Wakely in the comments to this answer, tarafından sayılı belgede belirtildiği gibi, (bu cevabın orijinal versiyonunda olduğu gibi - mea culpa) olmamalıdır.

Nedeni, Standart'taki özel bir kuralın, bir değer referansını kabul eden aşırı yükün, bir rvalue referansını kabul eden aşırı yükden daha uzmanlaşmış olduğunu belirtmesidir.

belirli bir çeşit için, kesinti her iki yönde de başarılı olur (yani, tip dönüşümler yukarıda sonra özdeş olan) ve her ikisi de P ve C++ 11 Standart paragrafında 14.8.2.4/9 Ortalama bağımsız değişken şablondan türü, argüman olarak kabul edilir değildi bir lvalue bir referans ve parametre şablondan türü olsaydı -

A (yukarıdaki ifade tip yerini önce) referans türleri edildi Diğer'dan daha uzman olmak; aksi takdirde [...]

Bu derleyici bir hata (the link to the bug report soruya ilişkin yorumlarda Marc Glisse tarafından sağlanmıştır) anlamına gelir.

bu hatayı Geçici çözüm ve T&& kabul sizin yapıcı şablon SağDeğerler geçirilen zaman sadece, bunu bu şekilde yeniden yazabilirsiniz GCC tarafından alınacak emin olmak için: Bir SFINAE-kısıtlamasını eklendi

#include <type_traits> 

    template<typename U, 
     typename std::enable_if< 
      !std::is_reference<U>::value 
      >::type* = nullptr> 
    Myclass(U&& rvalue):i(rvalue) 
    {cout<<i <<" template right reference" <<endl;i++;} 

Bu, derleyicinin, bir lvalue geçilirken, bu yapıcıyı aşırı yük setinden atmasını sağlar.

bir lvalue geçirildiğinde, aslında, T bazı X için X& olduğu sonucuna edilecektir (expression türünde size durumunda Myclass, pas) ve T&&X& içine çözer; Bir rıhtım geçilirken, diğer yandan, XX'dan (sizin ifade edeceğiniz ifade türünü, Myclass davanızdan) ve T&&X&&'a çözecektir.

SFINAE kısıtlaması, T'un bir referans türü olup olmadığı ve bir değiştirme hatası oluşturup oluşturmadığı kontrol edilmediğinden, yapıcınızın yalnızca argüman bir ifade ifadesi olduğunda dikkate alınacağı garanti edilir.

Yani hepsini özetlemek için:

İşte
#include <iostream> 
#include <type_traits> 

class Myclass 
{ 
    int i; 
public: 
    template<typename U> 
    Myclass(U& lvalue):i(lvalue) 
    { 
     std::cout << i <<" template light reference" << std::endl; 
     i++; 
    } 

    template<typename U, 
     typename std::enable_if< 
      !std::is_reference<U>::value 
      >::type* = nullptr> 
    Myclass(U&& rvalue):i(rvalue) 
    { 
     std::cout << i <<" template right reference" << std::endl; 
     i++; 
    } 
}; 

int main(int argc,char*argv[]) 
{ 
    Myclass a(0); 
    int x = 42; 
    Myclass b(x); 
    Myclass c(2); 
} 

bir live example olduğunu.

+2

Ancak, @MarcGlisse notlarında, [DR 1164] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1164), lvalue referans aşırı yükünün, " evrensel referans "bir –

+0

@JonathanWakely: Teşekkürler! Bunun farkında değildim. Cevabımı düzenlemem gerekecek –