Masalahnya di sini adalah, karena kelas digunakan T
, pada konstruktor Foo(T&&)
kita tidak melakukan deduksi tipe; Kami selalu memiliki referensi r-value. Artinya, konstruktor untuk Foo
benar - benar terlihat seperti ini:
Foo(int&&)
Foo(2)
berfungsi karena 2
merupakan nilai awal.
Foo(x)
tidak karena x
merupakan nilai yang tidak dapat mengikat int&&
. Anda dapat melakukannya std::move(x)
untuk melemparkannya ke jenis yang sesuai ( demo )
Foo<int&>(x)
berfungsi dengan baik karena konstruktor menjadi Foo(int&)
karena aturan runtuh referensi; awalnya ini Foo((int&)&&)
yang runtuh Foo(int&)
sesuai standar.
Sehubungan dengan panduan pengurangan "redundant" Anda: Awalnya ada panduan pengurangan template default untuk kode yang pada dasarnya bertindak seperti fungsi pembantu seperti:
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);
Ini karena standar menyatakan bahwa metode templat (fiksi) ini memiliki parameter templat yang sama dengan kelas (Hanya T
) diikuti oleh parameter templat apa pun sebagai konstruktor (tidak ada dalam kasus ini; konstruktor tidak templated). Kemudian, jenis parameter fungsi sama dengan yang ada di konstruktor. Dalam kasus kami, setelah instantiating Foo<int>
, konstruktornya terlihat seperti Foo(int&&)
, referensi-nilai dengan kata lain. Karenanya penggunaan di add_rvalue_reference_t
atas.
Jelas ini tidak berhasil.
Saat Anda menambahkan panduan deduksi "redundan" Anda:
template<typename T>
Foo(T&&) -> Foo<T>;
Anda diperbolehkan compiler untuk membedakan bahwa, meskipun setiap jenis referensi yang melekat T
dalam konstruktor ( int&
, const int&
, atau int&&
dll), Anda bermaksud jenis disimpulkan untuk kelas menjadi tanpa referensi (hanya T
). Ini karena kita tiba - tiba melakukan inferensi tipe.
Sekarang kita menghasilkan fungsi pembantu (fiksi) lain yang terlihat seperti ini:
template<class U>
Foo<U> MakeFoo(U&& u)
{
return Foo<U>(std::forward<U>(u));
}
// ...
auto f = MakeFoo(x);
(Panggilan kami untuk konstruktor diarahkan ke fungsi pembantu untuk keperluan kelas template argumen deduksi, sehingga Foo(x)
menjadi MakeFoo(x)
).
Ini memungkinkan U&&
untuk menjadi int&
dan T
menjadi sederhanaint