Comment passer une référence à un argument de nom de type de modèle

16

Existe-t-il un moyen de passer une référence en tant qu'argument à un argument de nom de type de modèle? Je veux dire donc au lieu de passer un int, par exemple, pour passer une référence à un int.

template <typename T>
struct Foo
{
    Foo(T arg) : ptr(arg) {}
    T ptr;
};

int main() 
{
    int* a = new int(6);
    Foo<decltype(a)> foo1(a); // ptr is a copy of a pointer
    Foo<decltype(&a)> foo1(&a); // ptr seems to be a pointer to a pointer
}

Je sais que je peux faire du membre 'ptr' une référence à un pointeur en le faisant T & dans la classe, mais je me demandais si cela pouvait être fait à partir d'un argument passé à l'argument modèle.

Poisson zèbre
la source
Je suppose que vous voulez rester decltype, car en prenant le titre à la lettre, vous pourriez simplement écrireFoo<int*&>
idclev 463035818

Réponses:

19

Vous cherchez Foo<decltype(a) &> foo1(a).

Une alternative plus obscure (qui fonctionne dans ce cas spécifique) est Foo<decltype((a))> foo1(a).

HolyBlackCat
la source
1
Ah ça a du sens, merci. Comment fonctionnent les doubles parenthèses en decltype ((a))? Comment cela en fait-il une référence?
Poisson zèbre
2
@Zebrafish Fondamentalement, decltypefonctionne différemment selon que vous lui donnez un nom de variable ou autre chose (une expression arbitraire). decltype(a)renvoie le type de la variable a(car vous lui avez simplement donné un nom de variable). decltype((a)), d'autre part, vous donne le type de l' expression (a) (qui l'est aussi int), avec une référence ajoutée qui indique la catégorie de valeur de l'expression. [1/2]
HolyBlackCat
(a)(ainsi que a) est une valeur l, qui est indiquée par &(les valeurs x sont représentées par &&, les valeurs pr ne changent pas du tout le type). Étant donné que les expressions n'ont jamais de types de référence, le fait de decltypepouvoir ajouter une référence au type ne peut pas provoquer de conflits. [2/2]
HolyBlackCat
3

Comme alternative à la réponse précédente, vous pouvez utiliser std :: reference_wrapper

std :: reference_wrapper est un modèle de classe qui encapsule une référence dans un objet assignable et copiable. Il est fréquemment utilisé comme mécanisme pour stocker des références dans des conteneurs standard (comme std :: vector) qui ne peuvent normalement pas contenir de références.

#include <functional>

template <typename T>
struct Foo
{
  Foo(T arg) : ptr(arg)
  {
  }
  T ptr;
};

int main()
{
  int* a = new int(6);

  Foo<std::reference_wrapper<int*>> foo1(std::ref(a));
  foo1.ptr[0] = 1;  // ok

  // This also works
  int* b = new int(6);
  Foo<std::reference_wrapper<decltype(b)>> foo2(std::ref(b));
  // and this too
  foo1 = foo2;

  // Or, if you use c++17, even this
  Foo foo3(std::ref(b));
}
Picaud Vincent
la source