Универсальная ссылка как поле класса

У меня есть шаблонная функция принимающая универсальную ссылку. У нее внутри объявлен класс. Реализацию этого класса я опущу. У меня несколько вопросов: будет ли поле data универсальной ссылкой? И не будет ли висячих ссылок?(как я знаю rvalue ссылки продливают время жизни объектов, но в данном случае я не до конца понимаю что будет происходить.) Сам код:

template<typename Type>
auto fn (Type&& param)
{
    class Wrapper
    {
    public:
        Wrapper(Type&& data) : data{std::forward<Type>(data)} {}

    public:
        Type&& data;

    };

    return Wrapper{std::forward<Type>(param)};
}

Ответы (2 шт):

Автор решения: AlexGlebe

Функций fn будет несколько экземпляров, и она универсальна.

Любой объект, хранящий ссылку на rvalue значение должен знать, что после конца команды, ссылка на этот объект неликвидна.

# include <utility>
# include <iostream>
class C{
public:
  C(){
      std::cout<<this<<"::C()"<<std::endl;
  }
  ~C(){
      std::cout<<this<<"::~C()"<<std::endl;
  }
};

template<typename Type >
auto fn (Type && param)
{
    class Wrapper
    {
    public:
        Wrapper(Type&& data) : data{std::forward<Type>(data)} {}

    public:
        Type&& data;

    };

    return Wrapper{std::forward<Type>(param)};
}

int main(){
    { C c1;
      auto x1 = fn(c1);
      std::cout <<"&x1.data="<<&x1.data<<std::endl; }
    auto x2 = fn( C());
    std::cout <<"&x2.data="<<&x2.data<<std::endl;
}

0x7ffd1883d24f::C() // c1
&x1.data=0x7ffd1883d24f
0x7ffd1883d24f::~C() // c1
0x7ffd1883d24f::C() // c2
0x7ffd1883d24f::~C() // c2
&x2.data=0x7ffd1883d24f

Временный объект C() создался, команда закончилась. Объект уничтожен. А у вас осталась только память от него. (Ссылка на удалённый объект)

→ Ссылка
Автор решения: HolyBlackCat

будет ли поле data универсальной ссылкой?

По определению, универсальная ссылка - это rvalue-ссылка на такой тип, который вы даете компилятору определить самостоятельно при создании этой ссылки.

Поэтому, параметр auto fn(Type &&param) - это универсальная ссылка, но только если вы позволили компилятору определить Type, а не указали его вручную.

А вот параметр Wrapper(Type &&data) и поле Type&& data; - не универсальные ссылки, потому что в обоих случаях Type фиксирован.

Но этим двум и не нужно быть универсальными, ведь внутри функции вы уже знаете, какой у вас аргумент, lvalue или rvalue.

И не будет ли висячих ссылок?(как я знаю rvalue ссылки продливают время жизни объектов

Все ссылки продлевают время жизни объектов, но они делают это ОДИН РАЗ. Если создать одну ссылку из другой, то эта новая ссылка уже ничего не продлевает.

Поэтому вся ваша функция ничего не продлевает.

Если вы напишете fn(MyClass{});, то временный объект будет жить только в этой строчке, до ; (более правильно, "до конца текущего full-expression"). Независимо от того, сохраните вы куда-то Wrapper или нет.

→ Ссылка