Como passar uma referência a um argumento de nome de tipo de modelo

16

Existe uma maneira de passar uma referência como argumento para um argumento de nome de tipo de modelo? Quero dizer, em vez de passar um int, por exemplo, para passar uma referência a um 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
}

Eu sei que posso fazer com que o membro 'ptr' seja uma referência a um ponteiro, tornando-o T & na classe, mas fiquei pensando se isso pode ser feito a partir do argumento passado para o argumento do modelo.

Zebrafish
fonte
Suponho que você queira ficar decltype, porque, ao pegar o título literalmente, você pode simplesmente escreverFoo<int*&>
idclev 463035818 25/03

Respostas:

19

Você está procurando Foo<decltype(a) &> foo1(a).

Uma alternativa mais obscura (que funciona neste caso específico) é Foo<decltype((a))> foo1(a).

HolyBlackCat
fonte
11
Ah, isso faz sentido, obrigado. Como funcionam os parênteses duplos no decltype ((a))? Como isso faz disso uma referência?
Zebrafish
2
@Zebrafish Basicamente, decltypefunciona de maneira diferente dependendo se você atribui um nome de variável ou outra coisa (uma expressão arbitrária). decltype(a)retorna o tipo da variável a(porque você simplesmente deu um nome à variável). decltype((a)), por outro lado, fornece o tipo da expressão (a) (que também é int), com referência adicional que indica a categoria de valor da expressão. [1/2]
HolyBlackCat
(a)(e também a) é um lvalue, indicado por &(xvalues ​​são representados por &&, prvalues ​​não alteram o tipo). Como as expressões nunca têm tipos de referência, o fato de decltypepoder adicionar referência ao tipo não pode causar conflitos. [2/2]
HolyBlackCat
3

Como alternativa à resposta anterior, você pode usar std :: reference_wrapper

std :: reference_wrapper é um modelo de classe que agrupa uma referência em um objeto copiável e atribuível. É freqüentemente usado como um mecanismo para armazenar referências dentro de contêineres padrão (como std :: vector) que normalmente não podem conter referências.

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