Jak przekazać odwołanie do argumentu nazwa typu szablonu

15

Czy istnieje sposób na przekazanie odwołania jako argumentu do argumentu o nazwie szablonu? Mam na myśli, że zamiast przekazać int, na przykład przekazać referencję do 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
}

Wiem, że mogę sprawić, by element „ptr” był odniesieniem do wskaźnika, ustawiając go jako T & w klasie, ale zastanawiałem się, czy można to zrobić z argumentu przekazanego do argumentu szablonu.

Zebrafish
źródło
Przypuszczam, że chcesz zostać decltype, ponieważ biorąc tytuł dosłownie, możesz po prostu napisaćFoo<int*&>
idclev 463035818

Odpowiedzi:

18

Szukasz Foo<decltype(a) &> foo1(a).

Bardziej niejasną alternatywą (która działa w tym konkretnym przypadku) jest Foo<decltype((a))> foo1(a).

HolyBlackCat
źródło
1
Ach, to ma sens, dzięki. Jak działają podwójne nawiasy w decltype ((a))? Jak to sprawia, że ​​jest to odniesienie?
Zebrafish
2
@Zebrafish Zasadniczo decltypedziała inaczej w zależności od tego, czy nadasz mu nazwę zmiennej, czy coś innego (dowolne wyrażenie). decltype(a)zwraca typ zmiennej a(ponieważ po prostu nadałeś jej nazwę zmiennej). decltype((a)), z drugiej strony, podaje typ wyrażenia (a) (które jest również int), z dodaną referencją, która wskazuje kategorię wartości wyrażenia. [1/2]
HolyBlackCat
(a)(oraz a) to wartość, na którą wskazuje &(wartości x są reprezentowane przez &&, wartości nie zmieniają wcale typu). Ponieważ wyrażenia nigdy nie mają typów odwołań, fakt, że decltypemożna dodać odwołanie do typu, nie może powodować żadnych konfliktów. [2/2]
HolyBlackCat
2

Alternatywą dla poprzedniej odpowiedzi jest użycie std :: reference_wrapper

std :: reference_wrapper to szablon klasy, który otacza odwołanie w kopiowalnym, możliwym do przypisania obiekcie. Jest często używany jako mechanizm do przechowywania referencji w standardowych kontenerach (takich jak std :: vector), które normalnie nie mogą przechowywać referencji.

#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
źródło