2013-08-31 22 views
5

Tôi đang xác định toán tử '*' để làm việc với mẫu lớp 'NumericArray'. Mã này là như sau:cảnh báo C4244: 'đối số': chuyển đổi từ 'double' thành 'const int', có thể mất dữ liệu

template <class T> 
NumericArray<T> NumericArray<T>::operator * (const T& factor) const 
{ 
    NumericArray<T> newArray(Size()); 
    for (int i = 0; i < Size(); i++) 
     newArray[i] = factor * GetE(i); 
    return newArray; 
} 

khi tôi cố gắng sử dụng một 'NumericArray' loại 'int' (NumericArray) với '*' điều hành khi 'tố' đối số là một đôi:

intArray1 = intArray1*2.5; 

tôi nhận được cảnh báo trình biên dịch như sau:

warning C4244: 'argument' : conversion from 'double' to 'const int', possible loss of data 

và arg 'tố' được cắt ngắn 2,5-2 (một int) trước khi nó được nhân chống lại các yếu tố của đối tượng 'NumericArray'. Có cách nào để ngăn chặn điều này xảy ra? Tôi nghĩ trong C++ nó là một vấn đề đơn giản của giao thức mặc định, trong đó int * double = double. Liệu tôi có sai? Nếu không, tại sao không áp dụng trong trường hợp này?

+1

+1 Đó là một câu hỏi đơn giản, nhưng có giá trị cho người dùng mới. Mẫu không tầm thường! –

Trả lời

9
intArray1 = intArray1*2.5; 

Tôi đoán intArray1 là loại NumericArray<int>. Nếu đúng như vậy, thì Tint. Vì vậy, trong biểu thức trên, 2.5double sẽ được chuyển đổi thành int, vì nó được chuyển đến đối số quá tải operator*(const int&).

Điều đó cũng có nghĩa là, 2,5 (gấp đôi) trở thành 2 (int) và factor về cơ bản là 2. Mất dữ liệu!

Một cách để khắc phục điều này là sử dụng chức năng template (như thành viên của lớp mẫu) như:

template<class T> //this is for class templatwe 
template<class U> //this is for function template 
NumericArray<T> NumericArray<T>::operator * (const U& factor) const 
{           //^^^^^^^ it is U now! 
    //your code 
} 

Đừng để bị bất ngờ bởi hai sử dụng template trong định nghĩa ở trên. Các ý kiến ​​nói những gì họ đang cho. Nếu bạn hiểu rõ điều đó, thì bạn cũng hiểu rằng tham số bây giờU thay vì T, nó có thể độc lập với T và do đó nó có thể là bất cứ điều gì bạn chuyển cho nó làm đối số. Không mất dữ liệu, như khi vượt qua đối số.

Bây giờ như bạn đã biết sản phẩm của intdouble hóa ra là double, thì tại sao trở NumericArray<int> từ chức năng trong trường hợp khi bạn vượt qua double với nó? Tôi nghĩ việc trả lại NumericArray<double> trở nên hợp lý hơn nếu đối số là double. Vì vậy, các sau dường như là đúng thực hiện:

template<class T> //this is for class templatwe 
template<class U> //this is for function template 
NumericArray<U> NumericArray<T>::operator * (const U& factor) const 
{   //^^^ CHANGED 
    NumericArray<U> newArray(Size()); //CHANGED HERE TOO! 
    for (int i = 0; i < Size(); i++) 
     newArray[i] = factor * GetE(i); 
    return newArray; 
} 

Chờ đã! Điều này có đúng không? Điều gì xảy ra nếu TdoubleUint? Ở trên có chính xác cùng một vấn đề như trước đó!

Vì vậy, đây là nỗ lực thứ ba:

template<class T> //this is for class templatwe 
template<class U> //this is for function template 
NumericArray<decltype(std::declval<T>() * std::declval<U>())> 
    NumericArray<T>::operator * (const U& factor) const 
{ 
    typedef decltype(std::declval<T>() * std::declval<U>()) R; //define R 
    NumericArray<R> newArray(Size()); //CHANGED HERE! 
    for (int i = 0; i < Size(); i++) 
     newArray[i] = factor * GetE(i); 
    return newArray; 
} 

Vì vậy, các kiểu trả về là:

NumericArray<R> 

nơi R là:

decltype(std::declval<T>() * std::declval<U>()); 

mà phụ thuộc vào loại sản phẩm của TU. Điều đó đúng bây giờ, ít nhất là tốt hơn nhiều.

Hy vọng điều đó sẽ hữu ích.

+0

+1 (và thậm chí sửa lỗi đó, tôi cũng không nắm giữ nhiều hy vọng cho giá trị trả về của 'GetE (i)'). – WhozCraig

+0

@WhozCraig: Đã chỉnh sửa nó với nhiều nội dung bổ sung. Hy vọng nó có ý nghĩa. – Nawaz

+0

Nawaz, tôi đánh giá cao nó, nhưng tôi đã hy vọng tìm được giải pháp không yêu cầu tôi phải khai báo lại và xác định lại tất cả các hàm, hàm và toán tử trong lớp mẫu NumericArray của tôi để kết hợp – user2736224

-1

Mã mẫu của bạn yêu cầu đối số và phần tử NumericArray có cùng thời gian, đó là lý do tại sao C++ cắt ngắn arg thành 2 trước khi nhân.

Để khắc phục điều đó, bạn nên mã hóa một cái gì đó giống như

template <class U> template<class T> 
NumericArray<T> NumericArray<T>::operator * (const U& factor) const 
{ 
    /***/ 
} 
+1

-1. Nó sẽ không biên dịch. – Nawaz

+0

tại sao không? Vui lòng giải thích –

+0

Xem câu trả lời của tôi. :-) – Nawaz

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