Vấn đề ở đây là, vì lớp được tạo khuôn mẫu T
, trong hàm tạo, Foo(T&&)
chúng ta không thực hiện khấu trừ kiểu; Chúng tôi luôn có một tài liệu tham khảo giá trị r. Đó là, hàm tạo Foo
thực sự trông như thế này:
Foo(int&&)
Foo(2)
hoạt động vì 2
là một giá trị.
Foo(x)
không phải vì x
là một giá trị không thể liên kết int&&
. Bạn có thể làm std::move(x)
để chuyển nó sang loại thích hợp ( bản demo )
Foo<int&>(x)
hoạt động tốt chỉ vì các nhà xây dựng trở thành Foo(int&)
do các quy tắc sụp đổ tham chiếu; ban đầu nó Foo((int&)&&)
sụp đổ Foo(int&)
theo tiêu chuẩn.
Liên quan đến hướng dẫn khấu trừ "dự phòng" của bạn: Ban đầu có một hướng dẫn khấu trừ mẫu mặc định cho mã về cơ bản hoạt động như một hàm trợ giúp như vậy:
template<typename T>
struct Foo {
Foo(T&&) {}
};
template<typename T>
Foo<T> MakeFoo(std::add_rvalue_reference_t<T> value)
{
return Foo<T>(std::move(value));
}
//...
auto f = MakeFoo(x);
Điều này là do tiêu chuẩn ra lệnh rằng phương thức mẫu (hư cấu) này có cùng tham số mẫu với lớp (Chỉ T
) theo sau bởi bất kỳ tham số mẫu nào như hàm tạo (không có trong trường hợp này; hàm tạo không được tạo khuôn mẫu). Sau đó, các loại tham số hàm giống như trong các hàm tạo. Trong trường hợp của chúng tôi, sau khi khởi tạo Foo<int>
, hàm tạo trông giống như Foo(int&&)
một tham chiếu giá trị trong các từ khác. Do đó việc sử dụng add_rvalue_reference_t
ở trên.
Rõ ràng điều này không hoạt động.
Khi bạn thêm hướng dẫn khấu trừ "dự phòng" của mình:
template<typename T>
Foo(T&&) -> Foo<T>;
Bạn cho phép trình biên dịch để phân biệt rằng, mặc dù bất kỳ loại tài liệu tham khảo kèm theo T
trong constructor ( int&
, const int&
hoặc int&&
vv), bạn dự định loại suy ra cho lớp để được mà không có tài liệu tham khảo (chỉ T
). Điều này là do chúng ta đột nhiên đang thực hiện suy luận kiểu.
Bây giờ chúng ta tạo một hàm trợ giúp (hư cấu) khác trông như thế này:
template<class U>
Foo<U> MakeFoo(U&& u)
{
return Foo<U>(std::forward<U>(u));
}
// ...
auto f = MakeFoo(x);
(Các lệnh gọi của chúng ta đến hàm tạo được chuyển hướng đến hàm trợ giúp cho mục đích khấu trừ đối số khuôn mẫu lớp, do đó Foo(x)
trở thành MakeFoo(x)
).
Điều này cho phép U&&
trở thành int&
và T
trở nên đơn giảnint