2012-11-10 33 views
5
template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) { 
    return x * y; 
} 

Đoạn mã này được lấy từ số C++11 FAQ của Stroustrup. Tôi hiểu những gì nó làm, đó là nhân hai đối tượng của các loại khác nhau. Điều làm tôi bối rối là cú pháp giữa các tham số mẫu và định nghĩa hàm. Điều gì đang xảy ra bên trong decltype? Tôi lấy nó rằng nó dereferencing một con trỏ T chưa được đặt tên được khởi tạo là 0 và nhân nó với con trỏ chưa được đặt tên là U bị hủy đăng ký và được khởi tạo theo cùng một cách. Tôi có đúng không?Cú pháp khó hiểu với các loại mẫu ẩn danh?

Vâng, nếu đây là những gì đang xảy ra, thì không phải là việc sử dụng các con trỏ, các tham chiếu và thêm dấu ngoặc đơn thừa không? Tôi không thể khởi tạo các loại như thế này trong khi duy trì hiệu quả mong muốn ?:

template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) { 
    return x * y; 
} 

này trông sạch hơn nhiều đối với tôi, và nó không có tác dụng tương tự khi nhân hai con số như trong lần đầu tiên ...

mul(4, 3); // 12 

Vậy tại sao Stroustrup nhấn mạnh vào sử dụng cú pháp phức tạp, dereference và cú pháp khởi tạo? Đây là, tất nhiên, trước khi ông giới thiệu cú pháp mới auto. Nhưng dù sao, câu hỏi của tôi là: Có sự khác biệt nào giữa hai hình thức khởi tạo kiểu trên không? Nơi ông sử dụng con trỏ và ngay lập tức dereferences họ thay vì chỉ đơn giản là làm những gì tôi đã làm, đó là để khởi tạo các loại không có con trỏ hoặc dereferencing? Bất kỳ phản ứng nào được đánh giá cao.

+0

Điều gì sẽ xảy ra khi đưa ra một 'T' không thể xây dựng từ một' int'? –

Trả lời

6

Phiên bản của bạn là không phải là tương đương.

  1. Phiên bản của bạn giả sử rằng cả hai TU đều có thể được xây dựng từ 0. Rõ ràng là không mong đợi điều này từ ma trận, nhưng chúng có thể được nhân lên.
  2. T(0) cho kết quả tạm thời (có thể liên kết với T&&) trong khi *(T*(0)) đưa ra tham chiếu đến đối tượng hiện có (nghĩa là, T&), do đó có thể chọn toán tử khác.

Tuy nhiên, phiên bản Stroustrup cũng không phải của bạn sẽ được sử dụng trong thực tế. Ở mức độ tương đương thực hiện biên dịch, người ta sẽ sử dụng:

template <typename T, typename U> 
decltype(std::declval<T>() * std::declval<U>()) mul(T x, U y); 

Nhưng nó không tận dụng lợi thế của Cuối Return Loại đặc điểm kỹ thuật, được xây dựng để cho phép trì hoãn việc kê khai của các kiểu trả về sau của chức năng khai lập luận : auto f(int, int) -> int. Khi các đối số đã được khai báo, chúng có thể là được sử dụng, điều này cực kỳ hữu ích cho decltype!

template <typename T, typename U> 
auto mul(T x, U y) -> decltype(x * y); 

Biểu mẫu sau được đảm bảo chọn cùng một trạng thái quá tải so với thân chức năng, với chi phí lặp lại (không may).

+0

Tại sao chúng ta không phải đặt 0 trong các tham số của 'std :: declval ()'? – 0x499602D2

+1

@David: không có đối số cho 'declval', vì vậy tôi không hoàn toàn hiểu câu hỏi của bạn, xin lỗi: x –

+0

Bạn đang làm' std :: declval () * std :: declval () 'nhưng cách chúng ta có biết đây là những con số không? Nơi tôi làm 'T (0)' Tôi đang khởi tạo nó thành 0; tại sao chúng ta không làm điều đó trong các tham số của 'declval'? – 0x499602D2

5

Phiên bản mã của bạn cho rằng T và U có các hàm tạo mặc định. Phiên bản Stroustrup không, nó tạo ra một đối tượng giả bởi dereferencing một con trỏ null. Tất nhiên, điều đó không quan trọng vì mã đó không có nghĩa là được thực hiện, nó chỉ có nghĩa là được phân tích cú pháp để biết loại kết quả.

4

decltype nội dung là ngữ cảnh chưa được đánh giá; nó không quan trọng những gì đang có, miễn là nó kết quả với một loại. Nghĩ trong một giây về T được định nghĩa như thế này:

struct T 
{ 
    int operator*(const U &) { return 2; } 
}; 

Nó không có constructor lấy int hay bất kỳ loại mà int là chuyển đổi thành; do đó, T(0) không dẫn đến đối tượng, ngay cả trong ngữ cảnh không được đánh giá là decltype. Do đó, việc sử dụng các tham chiếu null chưa được đánh giá có thể là cách dễ nhất để có được kiểu thích hợp.

Tóm lại: bạn không biết những gì các nhà thầu làm TU có, vì vậy bạn nên sử dụng tham chiếu null tham chiếu đối tượng giả của loại thích hợp.