Je suppose que non, mais je voudrais confirmer. Y a-t-il une utilisation pour const Foo&&
, où Foo
est un type de classe?
c++
c++11
constants
rvalue-reference
fredoverflow
la source
la source
const&&
c'est très important, bien qu'il ne dise pas pourquoi: youtube.com/watch?v=JhgWFYfdIho#t=54m20sRéponses:
Ils sont parfois utiles. Le projet C ++ 0x lui-même les utilise à quelques endroits, par exemple:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Les deux surcharges ci-dessus garantissent que l'autre
ref(T&)
cref(const T&)
fonctions et ne se lient pas aux valeurs r (ce qui serait autrement possible).Mise à jour
Je viens de vérifier la norme officielle N3290 , qui n'est malheureusement pas disponible publiquement, et elle contient en 20.8 les objets Function [function.objects] / p2:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Ensuite, j'ai vérifié le brouillon post-C ++ 11 le plus récent, qui est disponible publiquement, N3485 , et dans 20.8 Function objects [function.objects] / p2, il dit toujours:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
la source
const T&&
Est-ce que d' autres endroits sont utilisés?const T&&
empêche quelqu'un d'utiliser bêtement des arguments de modèle explicites du formulaireref<const A&>(...)
. Ce n'est pas un argument très fort, mais le coût duconst T&&
dépassementT&&
est assez minime.La sémantique pour obtenir une référence const rvalue (et non pour
=delete
) consiste à dire:Le cas d'utilisation suivant aurait pu être à mon humble avis un bon cas d' utilisation de la référence rvalue à const , bien que le langage ait décidé de ne pas adopter cette approche (voir l'article original de SO ).
Le cas: constructeur de pointeurs intelligents à partir d'un pointeur brut
Il serait généralement conseillé d'utiliser
make_unique
etmake_shared
, mais les deuxunique_ptr
etshared_ptr
peuvent être construits à partir d'un pointeur brut. Les deux constructeurs obtiennent le pointeur par valeur et le copient. Les deux permettent (c'est-à-dire au sens de: ne pas empêcher ) une utilisation continue du pointeur d'origine qui leur est passé dans le constructeur.Le code suivant se compile et les résultats avec double free :
int* ptr = new int(9); std::unique_ptr<int> p { ptr }; // we forgot that ptr is already being managed delete ptr;
Les deux
unique_ptr
etshared_ptr
pourraient empêcher ce qui précède si leurs constructeurs concernés s'attendaient à obtenir le pointeur brut comme une valeur constante , par exemple pourunique_ptr
:unique_ptr(T* const&& p) : ptr{p} {}
Dans ce cas, le double code gratuit ci-dessus ne se compilerait pas, mais ce qui suit:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Notez que cela
ptr
pourrait encore être utilisé après avoir été déplacé, donc le bogue potentiel n'est pas totalement parti. Mais si l'utilisateur est obligé d'appelerstd::move
un tel bogue tomberait dans la règle courante de: ne pas utiliser une ressource qui a été déplacée.On peut se demander: OK, mais pourquoi
T*
const&& p
?La raison est simple, pour permettre la création d'un
unique_ptr
pointeur depuis const . Rappelez-vous que la référence const rvalue est plus générique qu'une simple référence rvalue car elle accepte à la foisconst
etnon-const
. Nous pouvons donc permettre ce qui suit:int* const ptr = new int(9); auto p = std::unique_ptr<int> { std::move(ptr) };
cela n'irait pas si nous attendions juste une référence rvalue (erreur de compilation: impossible de lier const rvalue à rvalue ).
Quoi qu'il en soit, il est trop tard pour proposer une telle chose. Mais cette idée présente une utilisation raisonnable d'une référence rvalue à const .
la source
Ils sont autorisés et même les fonctions classées en fonction
const
, mais comme vous ne pouvez pas vous déplacer d'un objet const référencé parconst Foo&&
, elles ne sont pas utiles.la source
const T&, T&, const T&&, T&&
Outre std :: ref , la bibliothèque standard utilise également la référence const rvalue dans std :: as_const dans le même but.
template <class T> void as_const(const T&&) = delete;
Il est également utilisé comme valeur de retour dans std :: facultatif lors de l'obtention de la valeur encapsulée:
constexpr const T&& operator*() const&&; constexpr const T&& value() const &&;
Ainsi que dans 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;
Ceci est vraisemblablement pour conserver la catégorie de valeur ainsi que la constance du wrapper lors de l'accès à la valeur encapsulée.
Cela fait une différence si les fonctions qualifiées par const rvalue peuvent être appelées sur l'objet encapsulé. Cela dit, je ne connais aucune utilisation des fonctions qualifiées const rvalue ref.
la source
Je ne peux pas penser à une situation où cela serait utile directement, mais cela pourrait être utilisé indirectement:
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); }
Le T en g est T const, donc f x est un T const &&.
Il est probable que cela entraîne une erreur de comile dans f (quand il essaie de déplacer ou d'utiliser l'objet), mais f pourrait prendre un rvalue-ref afin qu'il ne puisse pas être appelé sur lvalues, sans modifier la rvalue (comme dans le trop simple exemple ci-dessus).
la source