2013-08-08 66 views
9

Vì mục đích giáo dục, tôi đang sửa lớp C++ số mẫu của riêng mình. Tôi muốn để có thể viết (v, w) cho dấu chấm sản phẩm của hai vectơ và do quá tải operator,() như sau:C++: Mặc định khởi tạo một kiểu tích phân trong một hàm mẫu

template<class T> 
const T Vector<T>::operator,(const Vector<T>& v) const 
{ 
    assertEqualSize(v); 

    T t; 
    for(size_t i=0; i<numElements; i++) { 
     t += elements[i] * v[i]; 
    } 
    return t; 
} 

Câu hỏi của tôi bây giờ là: làm thế nào để đúng cách khởi tạo t với giá trị hợp lý (ví dụ như 0.0 cho Vector<double>)? Tôi đã thử T t(); nhưng sau đó g ++ cho tôi biết, ví dụ: "double (*)()" không thể chuyển đổi thành "const double" tại câu lệnh return và rằng operator+=() sẽ không được xác định cho "(double(), double)".

Cảm ơn bạn rất nhiều!

+1

sử dụng '(v, w)' cho sản phẩm chấm là khá kỳ quặc. Tại sao không chỉ đơn giản là quá tải '*', tức là 'v * w' cho sản phẩm chấm? (đó là những gì tôi sử dụng). Trong 3D, sản phẩm vector có thể được thực hiện bằng cách sử dụng '^'. Tất nhiên, phép nhân bằng vô hướng hoặc ma trận cũng có thể được thực hiện bằng cách sử dụng (một quá tải khác) '*'. – Walter

+1

Tôi đồng ý rằng việc sử dụng lại toán tử dấu phẩy không phải là một ý tưởng hay. Nó sẽ dẫn đến mã khó hiểu. Thật không may, việc sử dụng lại '*' cũng không phải là một ý tưởng hay, bởi vì nó không rõ ràng, sản phẩm chéo là một ứng viên rõ ràng. Tôi thường cung cấp các chức năng cho các phép toán nhị phân liên quan đến vectơ. – juanchopanza

Trả lời

9

Những gì bạn cần là gọi giá trị khởi tạo, trong đó có tác động của zero-khởi tạo loại built-in:

T t{};  // C++11 
T t = T(); // C++03 and C++11 

Lý do này không làm việc

T t(); 

là nó là một khai báo của một hàm không tham số được gọi là t, trả về một T.

+0

Đó là một phiên bản templated của MVP phải không? – Borgleader

+0

@Borgleader, MVP là nhiều hơn 'Foo foo (Bar());', nhưng yeah. – chris

+0

@Borgleader nó chắc chắn là một VP, nhưng MVP thậm chí còn hơn V :) – juanchopanza

0

Mã của bạn không cho phép bất kỳ loại T, bao gồm cả những người dùng xác định, khi đơn giản giá trị khởi gọi constructor mặc định và do đó có thể không zero-khởi. Tôi sẽ ngạc nhiên nếu bạn dự định khác với các loại được xây dựng trong các loại T, nhưng người dùng mã của bạn có thể có các ý tưởng khác ... Bạn nên bảo vệ chống lại điều đó, ví dụ: qua SFINAE:

template<class T> 
struct is_complex { static const bool value = false; }; 
template<class U> 
struct is_complex<std::complex<U>> : std::is_floating_point<U> {}; 

template<class T> 
typename 
std::enable_if<std::is_floating_point<T>::value || is_complex<T>::value, 
       T>::type 
T Vector<T>::operator,(const Vector<T>& v) const 
{ 
    T t{}; // value-initialisation is now guaranteed to be zero-initialisation 
    /* ... */ 
} 

Tất nhiên, kiểu này SFINAE có thể được áp dụng cho class Vector<T> như một toàn thể (thay vì áp dụng nó với các phương pháp được lựa chọn).


Chỉ cần làm rõ: điều này hạn chế đáng kể các loại có thể T chỉ 6 loại phép (float, double, long double, và tương ứng std::complex<> loại). Tất nhiên, người ta có thể cho phép các loại số nguyên, nhưng tôi sẽ ngạc nhiên nếu bạn muốn hoạt động vector cho vectơ số nguyên.

+0

Không có cách nào để bảo vệ an toàn đối với các kiểu do người dùng định nghĩa có hàm tạo mặc định không thực hiện việc khởi tạo các phần tử của nó bằng 0. Mã của bạn đảm bảo khởi tạo bằng không như thế nào? – juanchopanza

+0

@juanchopanza Đối với các loại như vậy, SFINAE vô hiệu hóa chức năng này. Chỉ cho phép các loại dấu phẩy động hoặc 'std :: complex '. – Walter

+0

Vấn đề là làm thế nào để bạn xác định các loại như vậy? Bạn sẽ cần phải biết các nội bộ của constructor mặc định của họ, và xác định rằng họ không phải là không khởi tạo một cái gì đó nên được. Tôi không thể thấy SFINAE sẽ làm như thế nào. – juanchopanza

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