Sanırım hayır, ama onaylamak isterim. İçin herhangi bir kullanım var mıdır const Foo&&
, Foo
bir sınıf türüdür?
Sanırım hayır, ama onaylamak isterim. İçin herhangi bir kullanım var mıdır const Foo&&
, Foo
bir sınıf türüdür?
Yanıtlar:
Bazen faydalıdırlar. Taslak C ++ 0x'in kendisi bunları birkaç yerde kullanır, örneğin:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Yukarıdaki iki aşırı yükleme, diğerinin ref(T&)
ve cref(const T&)
işlevlerin (aksi takdirde mümkün olan) değerlere bağlanmamasını sağlar.
Güncelleme
Ne yazık ki kamuya açık olmayan resmi standart N3290'ı kontrol ettim ve 20.8 Function nesnelerinde [function.objects] / p2 var:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Ardından, halka açık olan en son C ++ 11 taslağını kontrol ettim, N3485 ve 20.8 İşlev nesneleri [function.objects] / p2'de hala diyor ki:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
const T&&
kullanılıyor mu?
const T&&
birisinin aptalca formun açık şablon değiştirgelerini kullanmasını engeller ref<const A&>(...)
. Bu korkunç güçlü argüman değil, ama maliyeti const T&&
üzerinde T&&
oldukça az.
Sabit bir değer referansı (için değil =delete
) almanın semantiği şunu söylemek içindir:
Aşağıdaki kullanım durumu , IMHO'nun const'a rvalue başvurusu için iyi bir kullanım örneği olabilirdi , ancak dil bu yaklaşımı benimsememeye karar verdi ( orijinal SO gönderisine bakın ).
Genellikle kullanımı tavsiye edilmektedir make_unique
ve make_shared
, ancak her ikisi de unique_ptr
ve shared_ptr
bir ham işaretçi yapılabilir. Her iki yapıcı da işaretçiyi değere göre alır ve kopyalar. Her ikisi de kurucuda kendilerine iletilen orijinal göstericinin devamlı kullanımına izin verir (yani: engelleme anlamında ).
Aşağıdaki kod, double free ile derler ve sonuçlanır :
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Her ikisi de unique_ptr
ve shared_ptr
ilgili kurucuları ham göstericiyi sabit bir değer olarak almayı beklerse , yukarıdakileri önleyebilir , örneğin unique_ptr
:
unique_ptr(T* const&& p) : ptr{p} {}
Bu durumda, yukarıdaki çift serbest kod derlenmez, ancak aşağıdakiler olur:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Not ptr
potansiyel hata tamamen gitmiş değil bu yüzden hala ondan sonra kullanılabilir, taşındı. Ancak, kullanıcının std::move
böyle bir hatayı çağırması gerekiyorsa şu ortak kural geçerlidir: taşınmış bir kaynağı kullanmayın.
Biri sorabilir: Tamam, ama neden T*
const&& p
?
Nedeni basit, unique_ptr
const işaretçisinden oluşturulmasına izin vermek . Sabit rvalue referansının hem ve hem de kabul ettiği için rvalue referansından daha genel olduğunu unutmayın . Böylece aşağıdakilere izin verebiliriz:const
non-const
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
sadece rvalue başvurusu beklersek bu olmazdı (derleme hatası: const rvalue ile rvalue bağlanamaz ).
Her neyse, böyle bir şey önermek için artık çok geç. Ancak bu fikir, sabit'e rvalue referansının makul bir kullanımını sunar .
Bunlara izin verilir ve hatta bunlara göre sıralanan işlevler const
, ancak belirtilen const nesnesinden hareket const Foo&&
edemediğiniz için yararlı değildirler.
const T&, T&, const T&&, T&&
Std :: ref yanında , standart kitaplık aynı amaç için std :: as_const içinde const rvalue referansını da kullanır .
template <class T>
void as_const(const T&&) = delete;
Ayrıca, sarılmış değer alınırken std :: isteğe bağlı içinde dönüş değeri olarak kullanılır :
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
Yanı sıra 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;
Bu muhtemelen değer kategorisinin yanı sıra sarılmış değere erişilirken sarmalayıcının sabitliğini korumak içindir.
Bu, const rvalue ref nitelikli işlevlerin sarmalanmış nesnede çağrılıp çağrılamayacağı konusunda bir fark yaratır. Bununla birlikte, const rvalue ref nitelikli işlevler için herhangi bir kullanım bilmiyorum.
Bunun doğrudan yararlı olacağı bir durum düşünemiyorum, ancak dolaylı olarak kullanılabilir:
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 g t const, yani f 'nin x, t const && olup.
Bu bir comile hata büyük olasılıkla bu sonuçlar ise f (taşımak veya nesneyi kullanmaya çalıştığında), fakat f çok basit olduğu gibi (rvalue değiştirmeden bu SolDeğerler çağrıda olamaz böylece bir rvalue-ref sürebilir yukarıdaki örnek).
const&&
, nedenini söylemese de çok önemli olduğunu söylüyor: youtube.com/watch?v=JhgWFYfdIho#t=54m20s