Как передать ссылку на аргумент typename шаблона

16

Есть ли способ передать ссылку в качестве аргумента аргументу типа имя шаблона? Я имею в виду, что вместо передачи int, например, чтобы передать ссылку на 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
}

Я знаю, что могу сделать член ptr ссылкой на указатель, сделав его T & в классе, но мне было интересно, можно ли это сделать из аргумента, который передается в аргумент шаблона.

рерио
источник
Я полагаю, вы хотите остаться decltype, потому что буквально взяв название, вы можете просто написатьFoo<int*&>
idclev 463035818

Ответы:

19

Ты ищешь Foo<decltype(a) &> foo1(a).

Более неясная альтернатива (которая работает в этом конкретном случае) Foo<decltype((a))> foo1(a).

HolyBlackCat
источник
1
Ах, это имеет смысл, спасибо. Как работают двойные скобки в decltype ((a))? Как это делает это ссылкой?
Данио
2
@Zebrafish По сути, decltypeработает по-разному в зависимости от того, даете ли вы ему имя переменной или что-то еще (произвольное выражение). decltype(a)возвращает тип переменной a(потому что вы просто дали ей имя переменной). decltype((a))с другой стороны, дает вам тип выражения (a) (который также int) с добавленной ссылкой, которая указывает категорию значения выражения. [1/2]
HolyBlackCat
(a)(также как a) является lvalue, который обозначен &(xvalues ​​представлены &&, prvalues ​​вообще не изменяет тип). Поскольку выражения никогда не имеют ссылочных типов, тот факт, что они decltypeмогут добавить ссылочную привязку к типу, не может вызвать каких-либо конфликтов. [2/2]
HolyBlackCat
3

В качестве альтернативы предыдущему ответу вы можете использовать std :: reference_wrapper

std :: reference_wrapper - это шаблон класса, который оборачивает ссылку в копируемый, назначаемый объект. Он часто используется в качестве механизма для хранения ссылок внутри стандартных контейнеров (например, std :: vector), которые обычно не могут содержать ссылки.

#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));
}
Пикауд Винсент
источник