2010-06-22 35 views
7

Các thuật toán tối thiểu thường được trình bày như thế này:min và chuyển tiếp hoàn hảo

template <typename T> 
const T& min(const T& x, const T& y) 
{ 
    return y < x ? y : x; 
} 

Tuy nhiên, điều này không cho phép các cấu trúc của mẫu min(a, b) = 0. Bạn có thể đạt được điều đó với một tình trạng quá tải thêm:

template <typename T> 
T& min(T& x, T& y) 
{ 
    return y < x ? y : x; 
} 

Những gì tôi muốn làm là thống nhất hai quá tải này qua chuyển tiếp hoàn hảo:

template <typename T> 
T&& min(T&& x, T&& y) 
{ 
    return y < x ? std::forward<T>(y) : std::forward<T>(x); 
} 

Tuy nhiên, g ++ 4.5.0 spits ra một cảnh báo cho min(2, 4) mà tôi trả lại một tham chiếu đến tạm thời. Tôi đã làm gì sai sao?


OK, tôi hiểu rồi. Vấn đề là với toán tử điều kiện. Trong giải pháp đầu tiên của tôi, nếu tôi gọi min(2, 4) toán tử điều kiện sẽ thấy một xvalue và do đó di chuyển từ chuyển tiếp x để tạo ra một đối tượng tạm thời. Tất nhiên nó sẽ là nguy hiểm để trở lại đó bằng cách tham khảo! Nếu tôi chuyển toàn bộ biểu hiện thay vì xy riêng rẽ, trình biên dịch không phàn nàn nữa:

template <typename T> 
T&& min(T&& x, T&& y) 
{ 
    return std::forward<T>(y < x ? y : x); 
} 

Được rồi, tôi đã thoát khỏi những tài liệu tham khảo cho các loại số học :)

#include <type_traits> 

template <typename T> 
typename std::enable_if<std::is_arithmetic<T>::value, T>::type 
min(T x, T y) 
{ 
    return y < x ? y : x; 
} 

template <typename T> 
typename std::enable_if<!std::is_arithmetic<T>::value, T&&>::type 
min(T&& x, T&& y) 
{ 
    return std::forward<T>(y < x ? y : x); 
} 
+0

Hmm có vẻ với tôi rằng ví dụ cuối cùng cũng tạo tạm thời theo FCD. Nhưng điều này có vẻ kỳ lạ: Có vẻ như tạo ra các thời gian để ràng buộc một 'int &&' thành một 'int' xvalue ?! Tôi nghĩ rằng xvalues ​​là refs rvalue ẩn danh mà có thể bị ràng buộc bởi tham chiếu rvalue mà không có thời gian tạo ra? Điều tương tự cũng xảy ra với mã đã sửa đổi của bạn, phải không? Kiểu trả về là 'int &&', và biểu thức trả về là một 'x'ue' int'. Tại sao trình biên dịch không cảnh báo nữa? –

+0

Nếu tôi đọc chính xác 8.5.3', nó nói rằng điều này tạo ra một int tạm thời khi ràng buộc tham chiếu đến xvalue: 'int x = 0; int && rx = (int &&)x; 'Tương tự như vậy khi sử dụng' std :: move'. Điều đó không thể là ý định, tôi nghĩ. –

+0

@Johannes: Bạn đang nói về phần nào trong 8.5.3? – fredoverflow

Trả lời

3

Có vẻ với tôi như bạn đang cố gắng đơn giản hóa vấn đề. Thật không may, nhận được nó hoàn toàn chính xác là decidedly không tầm thường. Nếu bạn chưa đọc N2199, bây giờ sẽ là thời điểm tốt để làm như vậy. Các tham chiếu Rvalue tiếp tục phát triển, vì vậy việc thực hiện tham chiếu của min và max có lẽ không chính xác nữa, nhưng ít nhất nó cũng là một điểm khởi đầu khá tốt. Cảnh báo: việc triển khai tham chiếu là số phức tạp hơn bạn sẽ thích!

+0

Dường như đề xuất đó đã bị từ chối. Bất kỳ ý tưởng tại sao? – jalf

+0

@jalf: Tôi nghi ngờ mọi người liếc nhìn việc thực hiện tham chiếu, và chạy đi la hét trong kinh hoàng. :-) –

+0

@Jerry: âm thanh hợp lý :) – jalf

1

Bạn không muốn chuyển tiếp hoàn hảo, tại đây, bạn muốn trả lại T& hoặc const T& và không bao giờ T&&. std::forward được thiết kế để chuyển một trong các tham số của bạn sang một hàm khác, không phải cho các giá trị trả về.

Tôi nghĩ rằng những gì bạn muốn là:

template <typename T> 
min(T&& x, T&& y) -> decltype(x) 
{ 
    return y < x ? y : x; 
} 

EDIT để tránh đung đưa vấn đề tham khảo:

template <typename T> 
struct dedangle { typedef T type; } 

template <typename T> 
struct dedangle<const T&> { typedef T type; } 

template <typename T, typename U> 
min(T&& x, U&& y) -> dedangle<decltype(0?y:x)>::type 
{ 
    return y < x ? y : x; 
} 

// dedangle is re-usable by max, etc, so its cost is amortized 
+0

Tôi không chắc chắn loại 'decltype (x)' nào, nhưng nó là 'T', không phải là tất cả những gì tôi muốn, hoặc' T && ', đó là những gì bạn nói tôi không nên làm. Đúng? – fredoverflow

+0

Phần 14.8.2.1 [temp.deduct.call] của tiêu chuẩn mô tả các biến đổi xảy ra trên các đối số của các hàm mẫu. 'decltype (x)' có thể dễ dàng là 'int &' hoặc 'const int &', trong khi kiểu trả về không trải qua quá trình này. Hãy xem ví dụ # 3 trong phần đó của tiêu chuẩn. –

+0

Tôi không đồng ý, 'decltype (x)' luôn giống như 'T &&'. Bạn có thể thuyết phục bản thân bằng cách chèn dòng 'static_assert (std :: is_same :: giá trị," ouch ");' vào mẫu hàm 'min'. – fredoverflow

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