2013-03-07 29 views
10

Có cách nào để tăng gấp đôi độ chính xác được trả về bằng cách nhân (để tránh tràn) không?Sửa đổi kiểu mẫu C++ T thành "T dài"?

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

Cái gì như:

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

Vì vậy mà dù 'int', 'dài', hoặc 'đúp' đã được đưa ra, một 'dài int', 'dài dài', hoặc 'dài gấp đôi 'sẽ được trả lại từ nhân.

Đây là câu hỏi chung. Tôi đang làm việc xung quanh nó bằng cách sử dụng một đôi trong nội bộ. Nhưng câu hỏi của tôi là liệu có bất kỳ cơ chế nào để quảng bá một loại cho biến thể "dài" của nó trong C++ không?

+0

Đây có thể là tốt hơn để chỉ sử dụng 'long' dài là' T' của bạn nếu bạn muốn tránh tràn. – Pubby

+4

'long' không phải là một vòng loại có thể được áp dụng cho tên loại; 'long int' là một tên kiểu không thể tách rời xảy ra với hai từ khóa' long' và 'int'. –

+0

Tôi không hiểu tại sao bạn muốn sử dụng "T dài". T là một tham số mẫu và nó có thể là bất kỳ kiểu nguyên thủy hoặc thể hiện của đối tượng mà bạn muốn, khi bạn sử dụng toán tử * dài. Trong một số trường hợp, bạn có thể truyền T đến lâu. – user1929959

Trả lời

13

Một giải pháp khả thi là để xác định loại đặc điểm riêng của bạn:

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

Đây là cách bạn sẽ sử dụng nó trong lớp học của bạn:

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

Và đây là một thử nghiệm nhỏ:

#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

Tùy thuộc vào mục đích sử dụng dự kiến, bạn có thể muốn bỏ qua 'loại' từ mẫu chung hoặc đảm bảo rằng bạn gặp lỗi biên dịch nếu bạn thử điều này với một kiểu không có phiên bản 'long'er và do đó sẽ tràn ra ngoài. Để an toàn, bạn có thể xác định các chuyên môn với 'int8_t' ->' int16_t', 'int16_t' ->' int32_t' và 'int32_t' ->' int64_t' để đảm bảo rằng bạn thực sự tăng kích thước ở mỗi giai đoạn. Ofc hơi kém di động vì đó là các kiểu tùy chọn, nhưng trên các hệ thống mã không chuyển sang 'multiply' có thể tràn, điều tốt nhất nên tránh. –

+0

@SteveJessop: Thật vậy, quan sát tốt.Nó chủ yếu phụ thuộc vào cách 'MyClass' có nghĩa là được sử dụng –

+1

@SteveJessop: Phần 'unsigned' được bao phủ bởi bình luận" và cứ thế ";-) –

2

@Andy có câu trả lời đúng, hoạt động khá tốt. Nhưng đối với những người muốn có một lỗi thời gian biên dịch nếu MyClass được khởi tạo với một loại mà không có giá trị 'dài', tôi đã kết hợp nó với bình luận tuyệt vời @ SteveJessop để cung cấp cho các giải pháp sau đây:

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

Ví dụ sử dụng 'longT':

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

Ví dụ cách dùng của MyClass:

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

Điều gì về cô đơn 'dài int' giữa tất cả những' intX_t 's? Điều gì xảy ra nếu 'std :: int32_t' là' typedef'ed thành 'long int'? –

+0

@ChristianRau: bắt tốt. Điều đó đã bị bỏ lại và đã bị xóa. –

Các vấn đề liên quan