Saya kira tidak, tapi saya ingin mengonfirmasi. Apakah ada gunanya const Foo&&
, dimana Foo
tipe kelasnya?
Saya kira tidak, tapi saya ingin mengonfirmasi. Apakah ada gunanya const Foo&&
, dimana Foo
tipe kelasnya?
Jawaban:
Mereka terkadang berguna. Draf C ++ 0x sendiri menggunakannya di beberapa tempat, misalnya:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Dua kelebihan beban di atas memastikan bahwa fungsi ref(T&)
dan lainnya cref(const T&)
tidak terikat ke nilai r (yang jika tidak dimungkinkan).
Memperbarui
Saya baru saja memeriksa standar resmi N3290 , yang sayangnya tidak tersedia untuk umum, dan ada di 20.8 Objek fungsi [function.objects] / p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Kemudian saya memeriksa draf post-C ++ 11 terbaru, yang tersedia untuk umum, N3485 , dan di 20,8 Objek fungsi [function.objects] / p2 masih mengatakan:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
const T&&
yang digunakan?
const T&&
mencegah seseorang dengan bodohnya menggunakan template eksplisit args dari formulir ref<const A&>(...)
. Itu bukan argumen yang sangat kuat, tetapi biaya const T&&
lebih T&&
cukup minim.
Semantik mendapatkan referensi nilai konstanta (dan bukan untuk =delete
) adalah untuk mengatakan:
Kasus penggunaan berikut bisa jadi IMHO kasus penggunaan yang baik untuk referensi nilai r ke const , meskipun bahasa memutuskan untuk tidak menggunakan pendekatan ini (lihat posting SO asli ).
Biasanya disarankan untuk menggunakan make_unique
dan make_shared
, tetapi keduanya unique_ptr
dan shared_ptr
dapat dibuat dari penunjuk mentah. Kedua konstruktor mendapatkan pointer berdasarkan nilai dan menyalinnya. Keduanya memungkinkan (yaitu dalam arti: tidak mencegah ) penggunaan lanjutan dari penunjuk asli yang diteruskan kepada mereka di konstruktor.
Kode berikut mengkompilasi dan hasil dengan gratis ganda :
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Keduanya unique_ptr
dan shared_ptr
dapat mencegah hal di atas jika konstruktor relevan mereka mengharapkan untuk mendapatkan pointer mentah sebagai nilai konstanta , misalnya untuk unique_ptr
:
unique_ptr(T* const&& p) : ptr{p} {}
Dalam hal ini kode bebas ganda di atas tidak akan dikompilasi, tetapi yang berikut akan:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Catatan itu ptr
masih bisa digunakan setelah dipindahkan, jadi potensi bug tidak hilang sama sekali. Tetapi jika pengguna diminta untuk memanggil std::move
bug seperti itu akan jatuh ke dalam aturan umum: jangan gunakan sumber daya yang dipindahkan.
Seseorang dapat bertanya: OK, tapi mengapa T*
const&& p
?
Alasannya sederhana, untuk memungkinkan pembuatan dari unique_ptr
pointer const . Ingatlah bahwa referensi nilai r lebih umum daripada hanya referensi nilai r karena ia menerima keduanya const
dan non-const
. Jadi kami dapat mengizinkan yang berikut:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
ini tidak akan berjalan jika kita hanya mengharapkan rvalue reference (kesalahan kompilasi: tidak dapat mengikat const rvalue ke rvalue ).
Bagaimanapun, ini sudah terlambat untuk mengusulkan hal seperti itu. Tapi ide ini memang menyajikan penggunaan yang wajar dari rujukan nilai r ke const .
Mereka diperbolehkan dan bahkan fungsi diberi peringkat berdasarkan const
, tetapi karena Anda tidak dapat berpindah dari objek const yang dirujuk const Foo&&
, mereka tidak berguna.
const T&, T&, const T&&, T&&
Selain std :: ref , pustaka standar juga menggunakan referensi rvalue const di std :: as_const untuk tujuan yang sama.
template <class T>
void as_const(const T&&) = delete;
Ini juga digunakan sebagai nilai kembalian di std :: opsional saat mendapatkan nilai yang dibungkus:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
Serta di std :: get :
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
Ini mungkin untuk menjaga kategori nilai serta keteguhan pembungkus saat mengakses nilai yang dibungkus.
Ini membuat perbedaan apakah fungsi yang memenuhi syarat nilai rvalue const dapat dipanggil pada objek yang dibungkus. Yang mengatakan, saya tidak tahu kegunaan apa pun untuk fungsi yang memenuhi syarat nilai rvalue const.
Saya tidak dapat memikirkan situasi di mana ini akan berguna secara langsung, tetapi ini mungkin digunakan secara tidak langsung:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
T dalam g adalah T konst, jadi f 's x adalah T konst &&.
Kemungkinan ini menghasilkan kesalahan comile di f (ketika mencoba untuk memindahkan atau menggunakan objek), tetapi f bisa mengambil rvalue-ref sehingga tidak bisa dipanggil pada lvalues, tanpa memodifikasi rvalue (seperti pada terlalu sederhana contoh di atas).
const&&
sangat penting, meskipun dia tidak mengatakan alasannya: youtube.com/watch?v=JhgWFYfdIho#t=54m20s