Tôi đổ lỗi std::function
(và bạn). Tôi đổ lỗi cho bạn, tất nhiên, vì yêu cầu std::function
để trả lại một tham chiếu lơ lửng, như được giải thích bởi Vittorio Romeo. Nhưng tôi cũng đổ lỗi cho mẫu xây dựng của std::function
vì không kiểm tra trường hợp này, mà phải ở hầu hết hoặc tất cả các trường hợp có thể phát hiện được tại thời gian biên dịch và do đó tạo ra một chẩn đoán. (Tôi sử dụng từ "đổ lỗi" chỉ để chỉ ra các lĩnh vực có thể cải thiện. Trong ý nghĩa đó, tôi cũng đổ lỗi cho bản thân mình vì không nghĩ đến việc thêm kiểm tra chính xác này vào việc thực hiện mẫu lớp học của riêng tôi.
Hãy hãy xem xét kỹ hơn chữ ký của hàm tạo. Tôi đã chọn trang định nghĩa cho mục đích này.
template<typename R, typename... Args>
template<typename F>
std::function<R(Args...)>::function(F f);
Có thể cấm tham chiếu treo ở đây. Một tham chiếu treo lơ lửng sẽ được trả lại từ số operator()
nếu và chỉ khi R
là tham chiếu đến tạm thời được trả lại bởi F
. Hãy xác định (trong phạm vi của cơ thể constructor):
std::is_reference<R>::value && ! std::is_reference<RF>::value
Có một:
using RF = decltype(f(std::forward<Args>()...));
Bây giờ chúng ta có thể gần như chắc chắn rằng một tài liệu tham khảo tòn ten sẽ được trả lại từ 's operator()
nếu function
tuy nhiên, trong đó, RF
có thể là loại lớp với toán tử chuyển đổi do người dùng xác định là R
. Mặc dù chuyển đổi này có thể vẫn không an toàn, chúng tôi không có đủ thông tin vào thời điểm này để quyết định và nên sai về mặt tổng quát.Rõ ràng, chúng ta có thể phát hiện xem là mục tiêu của R
là một lớp cơ sở công cộng của RF
(đây là giả định các điều kiện nêu trên là đúng):
std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value
tôi chỉ cho phép thừa kế nào ở đây vì std::function
chỉ có thể truy cập công cộng không nhập nhằng các lớp cơ sở. Trừ khi ai đó đã thực hiện std::function
một friend
trong số RF
vì một số lý do lạ. (. Kể từ khi chuyển đổi có thể được thực hiện bên trong đối tượng chức năng bao bọc, có lẽ là không cần phải làm điều này)
Đưa nó tất cả cùng nhau và đảo ngược logic, chúng ta có thể thêm tiền tố cơ thể function
constructor với:
using RF = decltype(f(std::forward<Args>()...));
static_assert(! std::is_reference<R>::value ||
std::is_reference<RF>::value ||
! std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value,
"Using this function object would result in a dangling reference in the function call");
Có lẽ vì lambda trả về véc tơ * theo giá trị * và không bằng tham chiếu. –
Nếu bạn thấy mình bao giờ quay trở lại một tham chiếu, hãy tự hỏi "đối tượng đó tôi đang đề cập đến cuộc sống ở đâu"? Nếu bạn không thể trả lời, bạn không nên làm điều đó. – StoryTeller
Vui lòng bật cảnh báo. Trình biên dịch của bạn có lẽ đã hét lên với bạn rằng đây là một ý tưởng tồi. – Yakk