So übergeben Sie einen Verweis auf ein Template-Typnamen-Argument

16

Gibt es eine Möglichkeit, eine Referenz als Argument an ein Argument für den Vorlagentypnamen zu übergeben? Ich meine dies, anstatt beispielsweise ein int zu übergeben, um einen Verweis auf ein int zu übergeben.

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
}

Ich weiß, dass ich das 'ptr'-Mitglied als Referenz auf einen Zeiger festlegen kann, indem ich es in der Klasse als T & bezeichne, aber ich habe mich gefragt, ob dies anhand eines Arguments möglich ist, das an das Vorlagenargument übergeben wird.

Zebrafisch
quelle
Ich nehme an, Sie möchten dabei bleiben decltype, denn wenn Sie den Titel wörtlich nehmen, können Sie einfach schreibenFoo<int*&>
idclev 463035818

Antworten:

19

Du suchst Foo<decltype(a) &> foo1(a).

Eine obskurere Alternative (die in diesem speziellen Fall funktioniert) ist Foo<decltype((a))> foo1(a).

HolyBlackCat
quelle
1
Ah das macht Sinn, danke. Wie funktionieren die doppelten Klammern in decltype ((a))? Wie macht es das zu einer Referenz?
Zebrafisch
2
@Zebrafish Funktioniert grundsätzlich decltypeunterschiedlich, je nachdem, ob Sie ihm einen Variablennamen oder etwas anderes geben (einen beliebigen Ausdruck). decltype(a)Gibt den Typ der Variablen zurück a(weil Sie ihr einfach einen Variablennamen gegeben haben). decltype((a))Auf der anderen Seite erhalten Sie den Typ des Ausdrucks (a) (der auch vorhanden ist int) mit einer zusätzlichen Referenz, die die Wertekategorie des Ausdrucks angibt. [1/2]
HolyBlackCat
(a)(sowie a) ist ein l-Wert, der durch angezeigt wird &(x-Werte werden durch dargestellt &&, pr-Werte ändern den Typ überhaupt nicht). Da Ausdrücke niemals Referenztypen haben, kann die Tatsache, dass decltypedem Typ Referenz hinzugefügt werden kann, keine Konflikte verursachen. [2/2]
HolyBlackCat
3

Alternativ zur vorherigen Antwort können Sie std :: reference_wrapper verwenden

std :: reference_wrapper ist eine Klassenvorlage, die eine Referenz in ein kopierbares, zuweisbares Objekt einschließt. Es wird häufig als Mechanismus zum Speichern von Referenzen in Standardcontainern (wie std :: vector) verwendet, die normalerweise keine Referenzen enthalten können.

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