2015-10-05 19 views
21

typename T ile şablonlanmış bir sınıf var. Bu örnekNeden benim templated işlevi 'T', 'T', 'T' = 'double' teşvik eder?

sorunum yok
myClass<double, 2> myObj_double_2(constructor args); 
myObj_double_2 = myObj_double_2 + 5.2; 

için ben bu çağrı bir işlevi,

template <typename T, size_t a> 
myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) { 
    return lhs += rhs; 
} 

myClass<T,a> myClass<T,a>::operator+=(const T& rhs) { 
    // Do addition, depends on 'a'. 
    return *this; 
} 

içerir.

Ben ancak

myObj_double_2 = myObj_double_2 + 5; 

Sonra derleyici bana böyle bir mesaj verir çağırırsanız - No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int').

Kodu, T'a dönüşen ek türlerin geçirilmesine izin vermek için bir şekilde yazabilir miyim (örneğin, çift (5) geçerli bir yapıcı çağrısıdır)?

+0

try myObj_double_2 = myObj_double_2 + 5.0; ' – 101010

+1

Evet - bu hiç bir zorlukla çalışmaz, ancak sorduğum sorunu çözmüyor (basit ve açık çözüm olmasına rağmen) – chrisb2244

+1

Hayır int-> çift" promosyon "var. –

cevap

32

, bir şablon parametresi için tüm kesintiler aynı sonucu olması gerekir.

Sizin durumunuzda, T için iki kesinti, double ve int üretir; bunlar aynı değildir ve kesinti başarısız olur.

sadece şablon argümanı kesinti için bir fonksiyon argüman kullanmak, diğeri undeduced yapmak olduğunu yapabilecekleriniz: std::common_type<T>::type, esasen sadece T olduğunu

template <typename T, std::size_t A> 
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2); 
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Not olduğunu ancak türüne nedeniyle arg2 artık bağımlı bir tür (adı, ::'un sağında görünür), sonuç çıkarılmaz. Bu nedenle, yalnızca ilk argüman kesintide yer alır ve T = double açık bir şekilde üretir ve ardından ikinci işlev parametresi yalnızca double türüne sahiptir ve normal dönüşümler gerçekleşir.

Genel kural olarak, şablon argümanı indirimi ::'u geçmez.

+0

Bu mükemmel, ama bence sen typename std :: common_type :: type'. Çözümünüz ayrıca 'const' ve' & 'nin eklenmesini de sağlar, bu harika – chrisb2244

+0

@ chrisb2244: Teşekkürler, düzeltildi. Referans değişikliklerini size bırakıyorum; Problem için önemli değiller. –

+1

'common_type' türünü bozar; muhtemelen burada alakalı değil, akılda tutulması gereken bir şey. –

17

aşırı yük çözünürlüğüne derleyici zaten double için mahsup ediliyor operator+ çünkü T için doğru bir aday bulmak için başarısız olur ve edebi 5 bir tam sayıdır. Çözüm: şablon argümanı kesinti kullanırken

template <typename T1, typename T2, size_t a> 
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) { 
    return lhs += T1(rhs); 
} 
+0

"T1" ve "T2" nin eşit olması durumunda, bu muhtemelen gereksiz bir kopyasla sonuçlanacaktır - parametreyi değer olarak alarak bir harekete izin verir (ve "int" durumunda daha hızlı olabilir) ve 'çifte'?) – chrisb2244

+4

@ chrisb2244 'T1 == T2' – BeyelerStudios

+0

durum için kısmen uzman olabilirsiniz. Sadece örtük dönüşümlere izin vermek istiyorsanız, daha sonra' T1 'türünü yerelleştirin. –

8

Şablon türü kesintisi ile ilgili sorunlara yol açıyorsunuz.

her iki bağımsız değişkeni T değerini deducing zaman "eşit ayakta" verilir ve iki argüman katılmıyorum bu durumda olan - bir başka Tdouble olması gerektiğini söylüyor, Tint olacağını söylüyor.

Bunu düzeltmenin doğru yolu Koenig operatörleriyle yapılır.

Yap += ve + ve sınıfın gibi friend ler ve inline uygulamak:

template<class T, size_t a> 
class myClass { 
    // etc 
public: 
    friend myClass operator+(myClass lhs, const T& rhs) { 
    lhs += rhs; 
    return std::move(lhs); 
    } 
    friend myClass& operator+=(myClass& lhs, const T& rhs) { 
    // do addition, depends on `a` 
    return *this; 
    } 
}; 

bu teknik garip bir şey yapar. Sınıfın şablon türüne bağlı olarak template operatörünü oluşturur. Bunlar daha sonra, + veya +='u çağırdığınızda, ADL (Koenig araması) aracılığıyla bulunur.

Şablon operatörü başına bu işleçlerden birini alırsınız, ancak şablon operatörleri değildir, bu nedenle const T& sonuçlandırılmamıştır ve dönüşüm beklendiği gibi gerçekleşir.