2012-10-15 25 views
7

Bu konuda SO ile ilgili başka soruları gördüm, ancak hiçbiri tam olarak açıklamıyor. sağ derleyicilerin aşağıdaki iki durumu ele alma yolları nedir?dönüşüm operatörü aşırı yükleme belirsizliği, derleyiciler farklılıklar

Örnek 1:

struct BB 
{ 
// generic cast 
template<typename T> 
operator T() const 
{ 
    return 0; 
} 

// string cast 
operator std::string() const 
{ 
    return string("hello"); 
} 
}; 

int main() 
{ 
    BB b; 
    string s = b; 
} 

Çıkış:

Bir tümü üzerinde farklı sonuçlar elde (-std = C++ 0 x) ile gcc 4.7.1, VS2010 ve VS2012 ile çalıştık
  • gcc 4.7.1: Tamam
  • VS2010: Tamam
  • VS2012: Başarısız: " dizeye BB 'den dönüştürülemez"

Örnek 2:

struct BB 
{ 
// generic cast 
template<typename T> 
operator T() const 
{ 
    return 0; 
} 

// string cast 
operator std::string() const 
{ 
    return string("hello"); 
} 
}; 

int main() 
{ 
    BB b; 
    string s = (string)b; 

Çıkış:

  • gcc 4.7.1: Yerine: aşırı dize çağrısı (bb &) kuşkulu
  • VS2010 olup: Tamam
  • VS2012: Başarısız: "BB'den string'e dönüştürülemiyor"

cevap

4

C stili dökümle ikinci sürümünüz belirsiz. Sorun, static_cast<std::string>'un BB sınıfının bir örneğini bir dizeye dönüştürebilmesinin iki yolu olmasıdır. Açık yol, bir dizeye doğrudan dönüştürmek için şablon olmayan std :: string cast operatörünüzü kullanmaktır. Daha dolambaçlı bir yol var ve hepsi VS2010'u buldu. Bu diğer yol, şablon döküm işlecinizi bir dize için bir BB dönüştürücüsüne dönüştürmek ve daha sonra bu ayırıcıyı kullanarak boş bir dize oluşturmaktır. Şablon cast operatörleri potansiyel olarak tehlikeli canavarlardır. Derleyiciye, BB'u - numaralı herhangi bir şeye dönüştürmeniz için gerekli araçları verdiniz.

İlk sürümünüz, std::basic_string(const _Alloc& __a) açık bir kurucu olduğundan bu sorundan kaçar. Açık yapıcılar, açık dönüşümlerle kullanılabilir, ancak örtük olmayanlar tarafından kullanılamaz. Bu kurucu ve belirsizliği yaratan bir ayırıcıya dönüştürme, bu yol örtülü bir dönüşümle kullanılamaz.

VS1012'nin ima edilen dönüşümde neden başarısız olduğu konusunda, VS2012'de bir hata olabilir veya C++ 11, BB'dan std::string'a kadar daha fazla yol açabilir. Ben bir C++ 11 uzmanı değilim. Ben acemi bile değilim.

Daha fazla öğe: kodunuzu daha da sefil başarısız olurdu şablon dönüşüm operatörü ile birlikte atama operatörü b den s almak için daha fazla yol oluşturur

std::string s; 
s = b; 

kullanmıştı. Sistem b'u std::string'a, char veya char*'a dönüştürmeli mi?

Alt satır: Şablon dönüştürme operatörlerini kullanımınızı yeniden düşünmelisiniz.

+0

Genel dönüştürme kullanıyorum, çünkü bir şeyleri destekliyor gibi yapıyorum :: any, ama belki de daha iyi bir yol var. Bu cevabı mksvetkov olarak işaretleyecektir mksvetkov oldukça benzer – Rolle

2

Bazı derleyicilerin altında başarısızlık nedeni, ne yaptığınızı anlamaya çalışırken farklı uzunluklarda gitmeleridir. Suçlu templated operatör çağrısıdır.

b.operator std::string()<std::string>; //invalid 
b.operator std::string <std::string>(); //also invalid, string takes no template arguments 
// a bunch more weird syntax constructions... 

konu olmasından kaynaklanır: this SO question şöyle açıklıyor

şablon bir operatörleri şablonu operatörü aramak için bir yolu yoktur, (eğer template<typename T> operator(); aramak istersem b.operator()<std::string>) açıkça çağrılacak lazım ama operator'dan sonraki adın şablon argümanına bağlı olduğunu, bu nedenle belirtmenin bir yolu yoktur. gcc ve VS2012, ne yaptığınızı anladı ve şablona ya da açıkça tanımlanmış bir => belirsiz çağrıya dönüştürebildiğini fark ettiler. VS2010 bunu yapmadı ve bunlardan birini çağırıyor, hata ayıklama yoluyla hangisini bulabiliyorsunuz.

Şablon uzmanlık böyle bir durumda yardım edebilirdim derleyici template<> olmadan bu işlev ve düzenli arasındaki farkı söyleyemem çünkü Ancak,

// string cast 
template<> 
operator std::string() const 
{ 
    return string("hello"); 
} 

başarısız olur tanımlamak için çalışıyor . Eğer prototipte bazı argümanlar olsaydı işe yaramazdı, ama operator typename herhangi bir ...

Uzun öykünün kısa olması - templated dönüşüm operatörlerinden kaçının.

+0

Ben hala örnek 1 ve 2 arasındaki farkı görmüyorum. Her iki durumda da, bir dize bir döküm yapılmalıdır, doğru, neden dizeleri atama operatörü BB bilmenin bir yolu yoktur? Ayrıca, sadece gcc örnekleri farklı – Rolle

+0

davranır gibi görünüyor ('b.operator std :: string() ;') işlevini çağırmaya çalışıyorsanız 'template işleç std :: string(); ' argüman 'std :: string' ve ikinci durumda' std :: string () 'dizisini çağırmaya çalışıyorsunuz, ancak std :: string bir şablon argümanı almıyor. – mtsvetkov

+1

@mtsvetkov - Farkın nedeni bu değil. Fark, açık dönüşüm yapıcıların ima edilen dönüşümlere yönelik sınırlama olmamasıdır. İlk örnek ima edilen bir dönüşüm, ikincisi, açık. –

İlgili konular