Russian Qt Forum
Ноябрь 25, 2024, 17:01 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: rvalue и operator ->  (Прочитано 24521 раз)
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #30 : Декабрь 25, 2018, 10:59 »

есть такая фраза: пьяный проспиццо, дурак - никогда(ц) Петр I

Ну хоть теперь ясно, с кем дело имеем Смеющийся.
Челом бьем).

твоя обертка со своим оператором 'стрелочка' косит под указатель.
не удивительно, что ты столкнулся с специфичным для указателей поведением.

Не обертка косит, а отсутствие оператора '.' заставляет использовать оператор '->' и мириться со специфичным для указателей поведением.

нет, не верно.
не нужно путать понятие "шаблон класса" и "шаблон функции".
...

Что ж, хотите, пишите так

Код
C++ (Qt)
struct Test
{
   void foo () && { ::std::cout << "Hello rvalue foo method." << ::std::endl; }
   void bar () && { ::std::cout << "Hello rvalue bar method." << ::std::endl; }
};
 

Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
 
   void exec () &&
   {
       ::std::move( m_value ).foo();
       ::std::move( m_value ).bar();
       // 100500 times using of ::std::move( m_value )
   }
};
 

вместо

Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
 
   void exec () &&
   {
       ::std::forward< T && >( m_value ).foo();
       ::std::forward< T && >( m_value ).bar();
   }
};
 

Даже отговаривать не буду)).
« Последнее редактирование: Декабрь 25, 2018, 11:02 от ssoft » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #31 : Декабрь 25, 2018, 11:32 »

В случае с std::forward экземпляр _Bers таки истину глаголит. На сколько я понимаю, вне контекста шаблонных аргументов функции(с forwarding references), std::forward особого смысла не имеет (ну разве что короче, чем static_cast). Правда, std::move тоже static_cast, так что с точки зрения реализации тут спорить особо не о чем Улыбающийся.
Записан

Пока сам не сделаешь...
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #32 : Декабрь 25, 2018, 11:34 »

Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
   void exec () &&
   {
       ::std::forward< T && >( m_value ).foo();
       ::std::forward< T && >( m_value ).bar();
   }
};
 
Даже отговаривать не буду)).

Пётр I был чертовски прав.
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #33 : Декабрь 25, 2018, 11:39 »

Правда, std::move тоже static_cast, так что с точки зрения реализации тут спорить особо не о чем Улыбающийся.

точка зрения реализации - это вообще монопенисуальный фактор.
значение имеет дизайн использования.

std::move очень простым и недвусмысленным образом отражает намерения автора кода.



Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #34 : Декабрь 25, 2018, 11:40 »

В случае с std::forward экземпляр _Bers таки истину глаголит. На сколько я понимаю, вне контекста шаблонных аргументов функции(с forwarding references), std::forward особого смысла не имеет (ну разве что короче, чем static_cast). Правда, std::move тоже static_cast, так что с точки зрения реализации тут спорить особо не о чем Улыбающийся.

Да, но в данном случае есть еще аргумент this, тип которого и указывается явно для метода (void exec () &&).
И forward и move по сути static_cast, но бесконечно перемещать объект для доступа к rvalue функциональности, как то некрасиво.

Да и при желании можно обобщить так

Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
 
   void exec () &
   {
       ::std::forward< T & >( m_value ).foo();
       ::std::forward< T & >( m_value ).bar();
   }
   void exec () const &&
   {
       ::std::forward< T const && >( m_value ).foo();
       ::std::forward< T const && >( m_value ).bar();
   }
   // ...
};
 

С move такой фокус не прокатит.
« Последнее редактирование: Декабрь 25, 2018, 12:25 от ssoft » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #35 : Декабрь 25, 2018, 11:49 »

С move такой фокус не прокатит.

и это совершенно правильно.
нельзя переместить неизменяемый объект.
он же неизменяемый, Карл!

сама хотелка совершить такое - это какой то бред далеко за гранью здравого смысла.


Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #36 : Декабрь 25, 2018, 11:57 »

С move такой фокус не прокатит.
и это совершенно правильно.
нельзя переместить неизменяемый объект.
он же неизменяемый, Карл!

сама хотелка совершить такое - это какой то бред далеко за гранью здравого смысла.

Ну хоть в чем то мы согласны), Карл!
Используйте forward, Карл, если нужно такое специфическое поведение, Карл!
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #37 : Декабрь 25, 2018, 12:19 »

Да и при желании можно обобщить так

Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
 
   void exec () &
   {
       ::std::forward< T & >( m_value ).foo();
       ::std::forward< T && >( m_value ).bar();
   }
   void exec () const &&
   {
       ::std::forward< T const && >( m_value ).foo();
       ::std::forward< T const && >( m_value ).bar();
   }
};
 

Можно. А можно и так:
Код
C++ (Qt)
template<class T> struct wrapper
{
   T m_value;
 
   void exec () &
   {
       static_cast< T & >( m_value ).foo();
       static_cast< T && >( m_value ).bar();
   }
   void exec () const &&
   {
       static_cast< T const && >( m_value ).foo();
       static_cast< T const && >( m_value ).bar();
   }
};

Это если к семантике придираться Улыбающийся. По смыслу, std::forward у меня больше ассоциируется с передачей аргумента функции куда-то дальше. Данный же случай больше похож на доступ к объекту, так что ни move ни forward особо не подходят, а выражается именно преобразование объекта к нужному типу.
Записан

Пока сам не сделаешь...
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #38 : Декабрь 25, 2018, 12:32 »

Это если к семантике придираться Улыбающийся. По смыслу, std::forward у меня больше ассоциируется с передачей аргумента функции куда-то дальше. Данный же случай больше похож на доступ к объекту, так что ни move ни forward особо не подходят, а выражается именно преобразование объекта к нужному типу.

Так тоже семантически понятно).
А использование move может и с толку сбить. Перемещаем - перемещаем, переместить не можем).
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #39 : Декабрь 25, 2018, 12:41 »

По смыслу, std::forward у меня больше ассоциируется с передачей аргумента функции куда-то дальше.

для этого он и был придуман.

Данный же случай больше похож на доступ к объекту, так что ни move ни forward особо не подходят, а выражается именно преобразование объекта к нужному типу.

просится что-то явно-говорящее:
Код:
access_to_temporary(m_value);




Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #40 : Декабрь 25, 2018, 12:42 »

Используйте forward, Карл, если нужно такое специфическое поведение, Карл!

оно нафиг не нужно, Карл!
нет разницы временный объект или нет, если он - константный, Карл!

Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #41 : Декабрь 25, 2018, 12:45 »

А использование move может и с толку сбить. Перемещаем - перемещаем, переместить не можем).

move тоже надо согласно смыслу употреблять, а не как в моём первом ответе Улыбающийся. Я таким иногда грешу, когда лень static_cast писать.

А свершится перемещение или нет, также зависит и от принимающей стороны.
Записан

Пока сам не сделаешь...
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #42 : Декабрь 25, 2018, 16:52 »

move и _есть_ статик каст к T&&
forward - это статик каст к & или && зависимости от того, какой тип у аргумента (void foo(Type &&t); - t это lvalue, а не rvalue)
Но у меня вопрос, внутри && ф-ии мемберы же тоже lvalue, нет? И спор о семантике (мув или форвард) бесполезен, форвард просто ничего не сделает.
И второй вопрос - а это вообще ок переиспользовать мувнутый объект? Улыбающийся foo() && может спокойно разрушить внутреннее состояние и bar() && отработает на пустом объекте
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #43 : Декабрь 25, 2018, 18:05 »

Но у меня вопрос, внутри && ф-ии мемберы же тоже lvalue, нет? И спор о семантике (мув или форвард) бесполезен, форвард просто ничего не сделает.

Как ни странно, но внутри && функций мемберы lvalue, в то время как в случае доступа через оператор '.' rvalue.

Код
C++ (Qt)
wrapper< Test >().m_value; // rvalue
 

Пока не нашел объяснение, почему это так.
Стандарт регламентирует применение свойств rvalue/lvalue к членам класса, подобно классификаторам const, volatile.
Тем не менее, это не выполняется для методов &&, а для const, volatile выполняется).

И второй вопрос - а это вообще ок переиспользовать мувнутый объект? Улыбающийся foo() && может спокойно разрушить внутреннее состояние и bar() && отработает на пустом объекте

Реализация методов подобных foo() && преследуют ограничения возможности их вызова и ничего больше. Про разрушение речь не идет.

Код
C++ (Qt)
Test().foo(); // Ok
Test test;
test.foo(); // Error
static_cast< Test && >( test ).foo(); // Ok
 

move всего лишь подчеркивает намерение перемещения.

Код
C++ (Qt)
::std::move( value ).foo(); // что и куда перемещаем? что имеется в виду?
container.append( ::std::move( value ) ); // содержимое value перемешается в контейнер и, возможно, сам value некорректен.
 

Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #44 : Декабрь 25, 2018, 18:25 »

Но у меня вопрос, внутри && ф-ии мемберы же тоже lvalue, нет?
да.  
поскольку у этих мемберов есть имена.

попробую проиллюстрировать на примере:

Код:
//казалось бы, должна принимать любые объекты, имеющие тип int&& 
void foo(int&&)
{}

int main()
{
    int&& v = std::move(10);

    // error: cannot bind ‘int’ lvalue to ‘int&&’
    foo(v);
}

казалось бы: типы совпадают, чего ему надо???
почему это rvalue-reference внезапно оказалась lvalue ?

потому что стандарт говорит:
временные объекты - это объекты, у которых нет имени.

Код:
// не просто выполняет преобразование к rvalue-reference
// она создает контекст, в рамках которого у xvalue нет имени
set_unigue( std::move(v) );



« Последнее редактирование: Декабрь 25, 2018, 18:34 от _Bers » Записан
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.391 секунд. Запросов: 23.