2013-03-07 13 views
10

Geri döndürülen kesinliği iki katına çıkarmak için herhangi bir yol var mı (taşmayı önlemek için)?"Uzun T" olmak için C++ şablon tip T'yi değiştirin.

template<class T> class MyClass { 
    T multiply (T a, T b) { return a * b; } 
} 

şey gibi:

long T multiply (T a, T b) { return a * b; } 

Yani 'int', 'uzun' veya 'çift' verildi olsun ki bir 'uzun int', uzun' 'uzun uzun', ya da çift 'çarpılarak iade edilir.

Bu genel bir sorudur. İçinde bir çift kullanarak etrafta çalışıyorum. Ama sorum şu: C++ 'daki "uzun" varyantına bir tür tanıtmak için herhangi bir mekanizma var mı?

template<typename T> 
struct add_long { typedef T type; }; 

template<> 
struct add_long<int> { typedef long int type; }; 

template<> 
struct add_long<double> { typedef long double type; }; 

template<> 
struct add_long<long int> { typedef long long int type; }; 

// And so on... 

Bu, ders esnasında kullanılırsa şekli şöyledir:

+0

Bu taşma kaçınmak istiyorsanız sadece 'T olarak 'uzun long' kullanmak daha iyi olacaktır. – Pubby

+4

'long', bir tür adına uygulanabilecek bir niteleyici değildir; 'long int',' long' ve 'int' adlı iki anahtar kelimeyle hecelenen bölünmez bir tiptir. –

+0

Neden "uzun T" kullanmak istediğinizi anlamıyorum. T, bir şablon parametresidir ve uzun sürdüğünüz gibi, ilkel tür veya nesne örneğini istediğiniz gibi olabilir * operatör geçersiz kılınır. Bazı durumlarda T'yi uzun süre kullanabilirsiniz. – user1929959

cevap

13

Muhtemel bir çözüm Kendi tip özelliği tanımlamaktır

template<class T> 
class MyClass { 
public: 
    typedef typename add_long<T>::type longT; 
    longT multiply (longT a, longT b) { return a * b; } 
}; 

Ve burada küçük bir testtir:

#include <type_traits> 

int main() 
{ 
    MyClass<int> m; 
    auto l = m.multiply(2, 3); 
    static_assert(std::is_same<decltype(l), long int>::value, "Error!"); 
} 
+3

Beklenen kullanıma bağlı olarak, jenerik şablondan 'type'ı çıkarmak isteyebilirsiniz, aksi takdirde bir derleme hatası aldığınızdan emin olun. Bunu, uzun bir sürüme sahip olmayan bir türle deneyin ve bu nedenle zaten taşacak. Güvenliğiniz için, daha sonra her aşamada boyutu artırdığınızdan emin olmak için 'int8_t' -> 'int16_t',' int16_t' -> 'int32_t' ve' int32_t' -> 'int64_t' ile uzmanlıkları tanımlayabilirsiniz. Bunlar, isteğe bağlı türler olduklarından biraz daha az taşınabilirdir, ancak sistemlerde kod, "çarpma" ye taşmaz, bu da en iyi şekilde kaçınılabilir. –

+0

@SteveJessop: Gerçekten, iyi gözlem.Esas olarak 'MyClass'ın –

+1

@SteveJessop olarak nasıl kullanıldığına bağlı olarak değişir:' İmzasız 'kısmı "ve benzeri" yorumuyla kaplıdır ;-); –

2

@Andy, iyi bir şekilde çalışan doğru cevabı var.

// --- Machinery to support double-precision 'T' to avoid overflow in method 'multiply' --- 
// Note: uncomment typedef if don't want compile-time errors 
// when no "long" type exists 
// ---- 
template<typename T> 
struct add_long { /*typedef T type;*/ }; 

template<> struct add_long<int8_t> { typedef int16_t type; }; 
template<> struct add_long<int16_t> { typedef int32_t type; }; 
template<> struct add_long<int32_t> { typedef int64_t type; }; 
template<> struct add_long<uint8_t> { typedef uint16_t type; }; 
template<> struct add_long<uint16_t> { typedef uint32_t type; }; 
template<> struct add_long<uint32_t> { typedef uint64_t type; }; 

template<> struct add_long<float> { typedef double  type; }; 
template<> struct add_long<double> { typedef long double type; }; 

: Ama Sınıfım hayır 'uzun' değerini orada olduğu bir türüyle örneği ise bir derleme zamanı hatası isteyenler için, aşağıdaki solüsyon vermek için @ SteveJessop mükemmel yorum ile kombine edilmiştir 'longT' Örnek kullanımı: Sınıfım

template<class T> class MyClass 
{ 
    // Note: a compiler error on the next line means that 
    //  class T has no double-precision type defined above. 
    typedef typename add_long<T>::type longT; 
public: 
    longT multiply (T a, T b) { return longT(a) * b; } 
} 

Örnek kullanım:

MyClass<float> my; 
printf("result = %lf\n", my.multiply(3.4e38, 3.4e38)); 
+0

Tüm bunlar "intX_t" ler arasındaki yalnız 'long int'? Ya std :: int32_t' 'long int''de yazılmıştır? –

+0

@ChristianRau: iyi yakalama. Bu kaldı ve kaldırıldı. –

İlgili konular