2013-03-07 4 views
10

(オーバーフローを避けるために)乗算によって返される精度を倍にする方法はありますか?C++テンプレートタイプTを「long T」に変更しますか?

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

ような何か:

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

'int型' か、 '長い'、または 'ダブル' が与えられたようにするため、 'long int型'、 '長い長い'、または「long double型'は掛け算から返されます。

これは一般的な質問です。私は内部的にダブルを使用してその周りに取り組んでいます。しかし、私の質問は、C++の "long"バリアントに型を昇格させるメカニズムがあるかどうかです。

+0

それはあなたがオーバーフローを避けたい場合は、ちょうどあなたの 'T'と '長いlong'を使用することがおそらく良いでしょう。 – Pubby

+4

'long'は型名に適用できる修飾子ではありません。 'long int'は、2つのキーワードlongとintで綴られた、分かれない型名です。 –

+0

なぜ「長いT」を使いたいのか分かりません。 Tはテンプレートパラメータであり、long * operatorがオーバーライドされているため、オブジェクトのプリミティブ型またはインスタンスになります。場合によっては、Tを長くキャストできます。 – user1929959

答えて

13

可能な解決策は、あなた自身の型特性を定義することです:

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... 

これは、あなたのクラスでそれを使用する方法である:

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

そしてここでは、小規模なテストです

#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

期待される用途に応じて、一般的なテンプレートから 'type'を省略するか、そうでなければコンパイルエラーとにかくオーバーフローするようなタイプで、これを試してみてください。安全のために、 'int8_t' - >' int16_t'、 'int16_t' - >' int32_t'、 'int32_t' - >' int64_t'で特殊化を定義して、実際に各段階でサイズを増やすことができます。 Ofcはオプションタイプなので移植性はやや劣りますが、システム上でコードが 'multiply'に移植されないとオーバーフローする可能性があります。これは避けるのが最善です。 –

+0

@SteveJessop:確かに、良い観察。主にMyClassがどのように使用されるかによって異なります。 –

+1

@SteveJessop:「署名されていない」部分は、「その他」のコメントでカバーされます;-) –

2

@Andyは正解ですが、これは非常にうまくいきます。

// --- 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; }; 

:MyClassのはNO「長い」の値が存在しないいるタイプでインスタンス化されている場合でも、コンパイル時にエラーをしたい人のために、私は以下のソリューションを提供するために、@ SteveJessopの優れたコメントでそれを組み合わせました「longT」の使用例:MyClassのの

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; } 
} 

使用例:

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

これらの 'intX_t'の間の孤独な' long int'はどうでしょうか? 'std :: int32_t'が' long int'に 'typedef'されているとどうなりますか? –

+0

@ChristianRau:良いキャッチ。それは残され、削除されました。 –

関連する問題