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

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

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: c++ новый стандарт (комитет)  (Прочитано 26369 раз)
ssoft
Программист
*****
Offline Offline

Сообщений: 584


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

Что Ок.
В том то и дело, что это бессмысленно. Не смыслва в void method() &&. Он по фунционалу ничем не будет отличаться от void method().  Такие вещи, демонстрирующие, что что-то компилируется, но не объясняющие суть, просто введут в ступор человека ,не знакомым с данной технологией. Многие побоятся спросить (чтобы не показаться глупыми), будут читать выше наведенные документации, где тоже std::cout << "Hello rvalue method " << ::std::endl; Честно, меня ввело в ступор - все говорят что нужно, но не говорят зачем. Затем дают заднюю....

Может где то это конструкция и нужна теоретически, но вы же не объяснили в чем смысл void method() &&

Единственный смысл
Код
C++ (Qt)
void method() &&
это ограничение возможности его вызова. Он может быть вызван только с помощью rvalue. Именно этим он и отличается от обычного
Код
C++ (Qt)
void method()
Если на практике еще не встречались с таким ограничением, это не значит, что это бессмысленно.
Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод (кроме конструктора), помечаем методы &. Что это дает? Экземпляр такого объекта обязательно имеет адрес в памяти. В отличие, например, от временного объекта, который вполне может быть распределен в регистрах процессора. Методы && предполагают обратные ограничения (экземпляр такого объекта не обязательно имеет адрес в памяти). И ничего больше.

Затруднений в понимании этого вопроса совсем не возникло, поэтому казалось, что вопрос тривиальный).

Как по мне, ваш пример для понимания "должен" выглядеть так.

Для меня как раз этот пример кажется странным и сложным (нетрадиционным) в использовании, но, в принципе, возможным для применения.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Не знаю, что такое Lerp и что должно быть понятно из вашего примера,
При таком отношении к предметной части Вы обречены Плачущий Ладно, считаем Вы пошутили. Lerp обычно синоним "линейной интерполяции"
Код
C++ (Qt)
template<class T>
T Lerp( const T & a, cont T & b, double w )
{
 return a * (1.0 - w) + b * w;
}
 
Предполагается что T поддерживает арифметиику, но средствами языка это никак не утверждается
но в с++20\23 будут "концепты".
Ага, занимаются, хорошо, значит мои пожелания не так уж глупы  Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

А что именно делает функция - это другой вопрос. Тут нужно либо искусство ёмко и понятно называть сущности, либо писать для них документацию.
Ставился вопрос/задача не "что делает", а "что должен иметь" (тот T) для того чтобы что-то делать

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #33 : Декабрь 10, 2019, 13:08 »

Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод (кроме конструктора), помечаем методы &. Что это дает? Экземпляр такого объекта обязательно имеет адрес в памяти. В отличие, например, от временного объекта, который вполне может быть распределен в регистрах процессора. Методы && предполагают обратные ограничения (экземпляр такого объекта не обязательно имеет адрес в памяти). И ничего больше.
Теперь понял, спасибо.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #34 : Декабрь 10, 2019, 13:09 »

При таком отношении к предметной части Вы обречены Плачущий Ладно, считаем Вы пошутили. Lerp обычно синоним "линейной интерполяции"

Про "линейную интерполяцию" я слышал где-то курсе на втором лет 10 назад в универе. С тех пор, верите, нет, ни в одной предметной области не пригодилось.
У меня проблемы более приземленные - вот тут без мьютекса в строчку лезут, вот тут вообще объект удалился в другом треде, вот тут за пределы буфера выходят потому что забыли проверить размер этого буфера, вот тут забыли free() позвать, вот тут кутешники забыли free() позвать... Какая предметная область, вы чего? Веселый
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #35 : Декабрь 10, 2019, 13:17 »

Теперь понял, спасибо.

Ну типичный пример это QImage::mirrored, если объект временный, то можно использовать его внутренний буфер и не копировать всю картинку, а прямо внутри "отразить".
В отличие от неконстантного метода, такой подход позволяет писать более "функциональный" код - объекты не меняются, то есть нет побочных эффектов, но при этом всё достаточно эффективно - нужна старая картинка, ну получите копию (будет медленнее), не нужна - ну напишите std::move чтобы явно показать намерение "выкинуть" старую картинку - зато эффективно и не мутабельно при этом.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #36 : Декабрь 10, 2019, 14:13 »

Ставился вопрос/задача не "что делает", а "что должен иметь" (тот T) для того чтобы что-то делать

С такой сигнатурой:
Код
C++ (Qt)
template<class T>
T Lerp( const T & a, const T & b, double w );
действительно много чего можно передать. Функция заявляет, что сможет работать практически с любыми типами T. Что вряд ли.

В С++20 можно будет писать, например, как-то так:
Код
C++ (Qt)
#include <QPoint>
#include <QVector3D>
#include <QDebug>
 
template <typename T>
concept Arithmetic =
   requires(T a, T b)
{
   a + b;
   a - b;
};
 
Arithmetic Lerp(const Arithmetic& a, const Arithmetic& b, double w)
{ return (b - a) * w; }
 
int main()
{
   qDebug() << Lerp(0, 10, 0.3);
   qDebug() << Lerp(QPoint{0, 0}, QPoint{10, 10}, 0.5);
   qDebug() << Lerp(QVector3D{0, 0, 0}, QVector3D{10, 10, 10}, 0.7);
 
   return 0;
}

Вывод:
Цитировать
3
QPoint(5,5)
QVector3D(7, 7, 7)

Так лучше? Улыбающийся
Записан

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

Сообщений: 3260


Просмотр профиля
« Ответ #37 : Декабрь 10, 2019, 14:18 »

ViTech

Вроде бы там разговоры о таком синтаксисе идут
Код:
template<Arithmetic T>
T Lerp(const T& a, const T& b, double w)

или
Код:
auto Arithmetic Lerp(const auto Arithmetic& a, const auto Arithmetic& b, double w)

Но это не точно Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #38 : Декабрь 10, 2019, 14:31 »

ViTech

Вроде бы там разговоры о таком синтаксисе идут
Код:
template<Arithmetic T>
T Lerp(const T& a, const T& b, double w)

или
Код:
auto Arithmetic Lerp(const auto Arithmetic& a, const auto Arithmetic& b, double w)

Но это не точно Улыбающийся

Тот пример я компилировал у себя прямо сейчас Улыбающийся. А вообще оба варианта работают. По крайней мере в текущем у меня gcc.

В смысле такие два варианта:
Код
C++ (Qt)
Arithmetic Lerp(const Arithmetic& a, const Arithmetic& b, double w);
 
template <Arithmetic T> T LerpT(const T& a, const T& b, double w);

С auto в концептах вроде тоже что-то видел, но нужно вспоминать, что именно Улыбающийся.
« Последнее редактирование: Декабрь 10, 2019, 14:37 от ViTech » Записан

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

Сообщений: 11445


Просмотр профиля
« Ответ #39 : Декабрь 10, 2019, 14:36 »

Так лучше? Улыбающийся
Намного, это то что я хотел. Только в содержательной части насвистели, (b - a) тоже можно, но тогда так
Код
C++ (Qt)
Arithmetic Lerp(const Arithmetic& a, const Arithmetic& b, double w)
{ return a + (b - a) * w; }
}
И боюсь что без этого ни до каких тонкостей языка дело не дойдет  Плачущий
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #40 : Декабрь 10, 2019, 15:13 »


Тот пример я компилировал у себя прямо сейчас Улыбающийся. А вообще оба варианта работают. По крайней мере в текущем у меня gcc.


А, прикольно. Просто там есть "проблема" что непонятно, что есть шаблонная функция, принимающая концепт, а что обычная функция, принимающая тип.
Но, возможно, это не проблема для компилятора (только для читающего) и на неё решили забить=)
Записан
Azazello
Самовар
**
Offline Offline

Сообщений: 103


Просмотр профиля
« Ответ #41 : Декабрь 10, 2019, 17:53 »

Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод (кроме конструктора), помечаем методы &. Что это дает? Экземпляр такого объекта обязательно имеет адрес в памяти. В отличие, например, от временного объекта, который вполне может быть распределен в регистрах процессора. Методы && предполагают обратные ограничения (экземпляр такого объекта не обязательно имеет адрес в памяти). И ничего больше.
Теперь понял, спасибо.

Что тут понятного, тут вообще ничего понятного нету.

Цитата: ssoft
   Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод помечаем методы &.

Ага, а если не пометить, то экземпляр объекта не будет обязательно распределен в памяти?

Т.е. если я напишу Test t, то что, распределение объекта в памяти зависит от наличия & для метода? Какая ерунда. Я следую инструкции написаной вами выше, и просто продолжаю размышления (отнесём к неясности выражения мысли). Возможно вы имеете в виду такую временность, Test().funct() &&? Что тоже ерунда, т.к. вы утрверждаете что this внутри этого объекта может не существать (цитата: т.к. экземпляр такого объекта не обязательно имеет адрес в памяти). Размазан по регистрам? По каким правилам?  

Пока что для меня void T::method() && таки до сих пор не имеет смысла.

Ну как не имеет. Если брать что-то наподобии "чтобы было", когда нам нужно не задумываться и использовать единый подход, даже если это не имеет особого смысла.

Я тоже часто пишу "чтобы было"
Код:
   class {
 
   const T& value() const   { return ...}
   T value() { return .. }
}

Заметте, для компилятора вызов этих методов одинаков. Я то  на уровне программиста оптимизировал тип возвращаемого значения на ссылку, тем самым предотвратив копирование, надеясь, что это ограничит клиентов этого метода на уровне соглашения - не надо делать const_cast. Отвечаешь за последствия ты. Но компилятор то уж точно здесь ни при чем.

В вашем же случае я вообще не могу ничего оптимизировать. Это просто дублирование кода.

Никаких отличий для компилятора, как бы эти функции не были помечены  - & или && или просто классическая не имеют. Это просто перегрузка. Просто дополнительные квалификаторы. Реализация "временного объекта" берет на себя программист. И вызов std::move лишь вызовет соответствующум функцию, а она может просто копировать. Все.

Пока буду считать так, если мне никто не ткнет обратное.
Вообще путаница конечно.
Термин временный объект подразумевает, что вы его будете куда то передавать, этож не технология компилятора, это просто принятые соглашения разработки, жить то он может вечно Улыбающийся

Как и термина "глобальная переменная" не существуют для компилятора (как и локальная), хотя все мы этим термином успешно пользуемся.
Хотя существует понятие стековой и переменной в куче (для компилятора).

Это я к чему эту дребень развел? Чтобы понять, на каком уровне мы находимся? На уровене компилятора? Для него нет оптимизации фунций с его точки зрения (& или && или const  в отличии от noexcept, finnaly....). Если на уровне программиста, то есть.
« Последнее редактирование: Декабрь 10, 2019, 22:31 от Azazello » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #42 : Декабрь 10, 2019, 19:15 »

Цитата: ssoft
   Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод помечаем методы &.

Ага, а если не пометить, то экземпляр объекта не будет обязательно распределен в памяти?

Если пометить только method() &, то у временного(rvalue) объекта нельзя будет такой метод вызвать.

Пример:
Код
C++ (Qt)
#include <iostream>
 
struct S
{
   void f()& { std::cout << "lvalue\n"; }
};
 
int main()
{
   S s;
   s.f();            // prints "lvalue"
   std::move(s).f(); // error
   S().f();          // error
}

Пока что для меня void T::method() таки до сих пор не имеет смысла.

Например, можно логи писать, с внутренними данными что-то делать. Не обязательно же что-то возвращать.
Записан

Пока сам не сделаешь...
Azazello
Самовар
**
Offline Offline

Сообщений: 103


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


Например, можно логи писать, с внутренними данными что-то делать. Не обязательно же что-то возвращать.

Так смысл в том, чтобы понять, где можно получить оптимизацию от вызовов:

void method()

и void method() &&.

Где, вызывая я один перегруженный метод, получу выгоду от вызова другого в разных условиях?
Ну хоть как то намекните.

Хочу заметить, тему я начал с хотелок конечно, но желание было чтобы компилятор хотя-бы const вызовы оптимизировал.

Я наверное неясно изъясняюсь. Но стремлюсь!

Вон Авваррон какие простыни пишет, никто с ним не спорит. Наверное думает, что что-то умное сказал, и все согласились.
На самом деле просто никто ничего не понял.

Ну или Igors - ну понятно! Ну, вам понятно, помогите  мне понять.

Тут же R/W пользователей с десяток, не больше. О чем общаться? Все в исходниках. Все всё прошли. Но какое желание держать лицо. Та давайте опустимся чуть ниже, все же фигню иногда делают. Все чего-то недопонимают. Но только попытка объяснить что либо вскрывает многие свои пробелы.

К примеру, я тоже доказывал что private virtual функция не имеет никакого смысла, думал - БОЖЕ, ЭТОЖЕ ОСНОВЫ.
Ну, правда, до сих пор смысла не понимаю, зачем они так сделали, но таки она работает, успешно компилируется и благодаря Маерсу (запретил бы его, как и Александреску) часто используется.

« Последнее редактирование: Декабрь 11, 2019, 10:08 от Azazello » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #44 : Декабрь 11, 2019, 08:19 »

Цитата: ssoft
    Например, хочется чтобы экземпляр объекта был обязательно распределен где-то в памяти (стек или куча) перед тем, как будет вызван какой-либо его метод помечаем методы &.

Ага, а если не пометить, то экземпляр объекта не будет обязательно распределен в памяти?

Т.е. если я напишу Test t, то что, распределение объекта в памяти зависит от наличия & для метода? ...

 Смеющийся Не, не, не. Я такого не писал). Возможность вызова метода & зависит от того, распределен ли объект в памяти.

Что тоже ерунда, т.к. вы утрверждаете что this внутри этого объекта может не существать (цитата: т.к. экземпляр такого объекта не обязательно имеет адрес в памяти). Размазан по регистрам? По каким правилам? 

Если явно this не используете внутри, экземпляр объекта умещается в регистры и компилятор может выполнить соответствующую оптимизацию, то почему бы и нет.
Посмотрите, например, сюда https://docs.microsoft.com/ru-ru/archive/msdn-magazine/2015/may/compilers-what-every-programmer-should-know-about-compiler-optimizations-part-2

Это я к чему эту дребень развел? Чтобы понять, на каком уровне мы находимся? На уровене компилятора? Для него нет оптимизации фунций с его точки зрения (& или && или const  в отличии от noexcept, finnaly....). Если на уровне программиста, то есть.

Явное указание & или && для метода - это оптимизация уровня программиста, конечно.

Попробую примеры сформулировать.

1. Реализация какого-нибудь вычислителя с хранением результата вычислений.

Код
C++ (Qt)
struct Calculator
{
   using Values = ::std::vector< double >;
 
   Calculator ( Values values )
   {
       m_squared.reserve( values.size() );
       for ( const auto & value, values )
       {
               m_squared.push_back( value * value );
       }
   }
 
   Values squared () & { return m_squared; }; // get squared by coping
   Values squared () && { return ::std::move( m_squared ); }; // get squared by moving
 
private:
   Values m_squared;
};
 
void foo ()
{
   Calculator::Values v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
   Calculator calculator( v );
   auto squared_by_coping = calculator.squared(); // coping
   auto squared_by_moving = Calculator( v ).squared(); // moving
}
 

2. Запрет использования методов, если объект не является rvalue

Код
C++ (Qt)
class Logging
{
   using Pattern = ::std::string;
   using Key = ::std::string;
   using Value = ::std::string;
 
   Logging ( Pattern ) { /*формирование шаблона сообщения*/ }
   ~Logging () {} { /*вывод в файл/консоль/и т.п.*/ }
   Logging && arg ( Key key, Value value ) && { /*заполнение полей шаблона сообщения*/ };
};
 
void foo ()
{
   Logging( "Hello, ${username}!" ).arg( "username", "German" ); // так работает
 
   Logging log( "Hello, ${username}!" );
   log.arg( "username", "German" ); // а такое использование запрещено
}
 
Записан
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


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