2011-10-26 34 views
18

Yukarıdaki gibi bir soru, aşağıdaki gibi daha fazla ayrıntı:Bir örtük yayınlamayı nasıl önleyebilirim -> int?

Anlamak için bir sınıfım var Money ... iyi, ne olduğunu tahmin ettiniz. Aşağıdaki kod mümkün değildir bu yüzden, (*) etkileşim Money ve double izin vermeyerek hakkında çok sıkı duyuyorum: Şimdi "örneğinde olduğu gibi, int ile Money çoğalmasını sağlayan hakkında düşündüklerim

Money m1(4.50); 
double d = 1.5; 
Money m2 = m1 * d; // <-- compiler error 

her biri 4,50 $ için 6 dilim kek var (yani gidip bir yere daha ucuz bir kek bul.)

class Money 
{ 
    Money(); 
    Money(const Money & other); 
    explicit Money(double d); 
    ... 
    Money & operator*=(int i); 
    ... 
} 
inline const Money operator*(const Money & m, int i) { return Money(m) *= i; } 
inline const Money operator*(int i, const Money & m) { return Money(m) *= i; } 
çalışıyor

, ama ... maalesef C++ kadar aniden benim ilk kod parçacığı derleyip double den int için örtülü yayınları yapar. Bunu istemiyorum. Bu durumda örtük yayınları önlemek için herhangi bir yolu var mı?

Teşekkürler! - Robin

(*) Nedeni: Ben çok 'double tüm Money lı malzeme işleme eski kod var ve ben Money çalıştırmak herşeyi kadar karıştı o tür istemiyoruz.

Düzenleme: Para için ek kurucular.

Düzenleme: Herkes, yanıtlarınız için teşekkürler. Hemen hemen hepsi harika ve yardımseverdi. R. Martinho Fernandes'in yorumu "inline const Money operator*(const Money & m, double d) = delete; yapabilirsin" cevabı aslında oldu (C++ 11 destekli derleyiciye geçtiğimde). Kerrek SB, iyi bir C++ 11 alternatifi vermedi, fakat benim kullandığım şey, aslında Nicola Musatti'nin "aşırı yük long" yaklaşımı. Bu yüzden cevabını "cevap" olarak işaretliyorum (ayrıca tüm yararlı fikirlerin cevabına yorum getirdiği için). Yine teşekkürler!

+1

Para yapıcılarını göster – mloskot

+0

Metindeki "C" ile "C++" arasındaki başvurunuzu değiştirdim. – xanatos

+0

Ancak, mloskot tarafından düşünülürse, örtük bir dönüşüm çift olabilir -> Para – xanatos

cevap

8

Sen genişletilmiş atama operatörünün özel yüklenmesi için deklarasyon ekleyebilirsiniz:

private: 
    Money & operator*=(double i); 
+2

Hatta bir 'is_same' veya 'is_integral' kontrolüne sahip bir şablon yapsın! –

+0

Sadece "Money m * = d;' kullanımı için çalışır. Ama nasıl (dış/küresel) operatörler inline const Para operatör * (const Money & m, çift d) ve inline const Para operatör * (çift d, const Money & m) 'saklardım. Orada 'özel' kurmanın bir yolu yok, değil mi? – Robin

+5

@Robin: C++ 11'de inline const yapabilirsiniz. Para operatör * (const Money & m, double d) = delete; '. Derleyiciniz bunu destekliyorsa, onu kullanın! –

15

Nasıl bir şablon hakkında artı özellik çek zamanlı derleme:

#include <type_traits> 

// ... 

template <typename T> 
Money & operator*=(const T & n) 
{ 
    static_assert(std::is_integral<T>::value, "Error: can only multiply money by integral amounts!"); 
    // ... 
} 
+0

Teşekkür eder, işe yarıyor. Tek sorun şu ki: Şimdi derleyici hataları alıyorum ama onları paralı hale getiriyorum. Yani 'delete' veya 'enable_if' daha da iyi olabilir. (Ya da sadece şirket kurallarına uygun değilse, C++ 11 uyumlu bir derleyiciye geçiş yapmak ...) – Robin

+1

@Robin: şablon örneklemesi sırasında bir hata oluştuğunda (burada durum böyle) derleyici size örnek yığını vermeli ve yığındaki alt giriş, operatörün fiilen çağrıldığı dosya ve satır olacaktır. –

0

Eğer az sayıda oluşturabilir İstediğiniz tüm özelliklere sahip olan tutucu türü, daha sonra Money gibi diğer türlerle arabirim kurmak için bunu kullanın. şablonu ve "kavramı" kontrolleri kullanarak

  • ya
  • veya kullanarak "yasak" aşırı yükleme yaparak edilir kullanma

boğan: Bunu sağlamak için iki yoldan

7

düşünebiliriz C++ 11 çözümü. C++ 11, özellikle sizin durumunuz için delete anahtar kelimesini tanıtıyor!

sınıfta
  • , private
  • yöntemi tanımlamak ve beklemeyin yöntem bildirmek: bu konuda gitmek için

    Money& operator*=(int i); 
    Money& operator*=(float f) = delete; 
    
    Money operator*(Money m, int i) { return m*i; } 
    Money operator*(Money m, float f) = delete; 
    
    Money operator*(int i, Money m) { return m*i; } 
    Money operator*(float f, Money m) = delete; 
    

    eski yolu (C++ 03) çift oldu şikayetçi

İkincisi, sınıf yöntemi durumunda bir korumadır ve serbest yöntem durumunda tek yoldur. şablonunu kullanarak


başka çözüm); O sadece bağlantı anda tespit ne üzücü ... ve delete kelime sadece çok daha güzel. std::enable_if veya static_assert'u kullanabilirsiniz: Biri, aşırı yük setinden (SFINAE) işlevi silerken diğeri, örnekleme hatası (derleyici hatası) oluşturacaktır.

Örnek: static_assert için

// For enable_if 
template <typename T> 
std::enable_if<std::is_integral<T>::value, Money&> operator*=(T t); 

template <typename T> 
std::enable_if<std::is_integral<T>::value, Money> operator*(Money m, T t); 

template <typename T> 
std::enable_if<std::is_integral<T>::value, Money> operator*(T t, Money m); 

örnekleri (sadece normal bir assert gibi gerçekten) daha doğal.


Eğer varsa, aşırı yüklenmeyi + delete tercih ederim. Eğer şablon kasasında bir geri dönüş yoksa muhtemelen en iyi çözümdür, çünkü derleyici hatalarını linker olanlardan daha kolay bir şekilde düzeltmek kolaydır.

+0

Teşekkürler, temelde diğer cevapları özetlediniz, eklediğiniz 'enable_if 'ekledik ve ilginç görünüyorlar (' delete' MSVC2010 ile çalışmaz,' static_assert', paramda derleyici hatası üretir, işletmeciyi kullanmadığım yerde değil). Ancak, ben çalışmak için kod "enable_if" örneği alamıyorum. Kod iyi görünüyor, bu yüzden benim korkarım 'enable_if' MSVC2010'un desteklemediği başka bir C++ 11 özelliğidir ... – Robin

+0

@Robin: hangi' enable_if' kullanıyorsunuz? FYI 'std :: enable_if' ve' boost :: enable_if', 'std :: enable_if' arasında' 'boost :: enable_if_c' 'ile eşdeğer arasında küçük bir arayüz farkı vardır. Boost çözümü C++ 03 ve C++ 11'de çalışmaktadır ve std çözümü yeni bir işlevsellik gerektirmediğinden çalışmalıdır. –