Cómo pasar una referencia a un argumento de nombre de tipo de plantilla

16

¿Hay alguna manera de pasar una referencia como argumento a un argumento de nombre de tipo de plantilla? Quiero decir que en lugar de pasar un int, por ejemplo, pasar una referencia a 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
}

Sé que puedo hacer que el miembro 'ptr' sea una referencia a un puntero al convertirlo en T en la clase, pero me preguntaba si esto se puede hacer desde el argumento que se pasa al argumento de plantilla.

Pez cebra
fuente
Supongo que quiere quedarse decltype, porque tomando el título literalmente, simplemente podría escribirFoo<int*&>
idclev 463035818

Respuestas:

19

Usted está buscando Foo<decltype(a) &> foo1(a).

Una alternativa más oscura (que funciona en este caso específico) es Foo<decltype((a))> foo1(a).

HolyBlackCat
fuente
1
Ah, eso tiene sentido, gracias. ¿Cómo funcionan los paréntesis dobles en decltype ((a))? ¿Cómo lo hace eso una referencia?
Pez cebra
2
@Zebrafish Básicamente, decltypefunciona de manera diferente dependiendo de si le das un nombre de variable o algo más (una expresión arbitraria). decltype(a)devuelve el tipo de la variable a(porque simplemente le dio un nombre de variable). decltype((a)), por otro lado, le proporciona el tipo de expresión (a) (que también lo es int), con una referencia adicional que indica la categoría de valor de la expresión. [1/2]
HolyBlackCat
(a)(así como a) es un valor l, que se indica mediante &(los valores x están representados por &&, los valores no cambian el tipo en absoluto). Dado que las expresiones nunca tienen tipos de referencia, el hecho de que decltypepueda agregar referencias al tipo no puede causar ningún conflicto. [2/2]
HolyBlackCat
3

Como alternativa a la respuesta anterior, puede usar std :: reference_wrapper

std :: reference_wrapper es una plantilla de clase que envuelve una referencia en un objeto asignable y que se puede copiar. Con frecuencia se usa como mecanismo para almacenar referencias dentro de contenedores estándar (como std :: vector) que normalmente no puede contener referencias.

#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
fuente