Re[36]: Зачем плюс?
От: rg45 СССР  
Дата: 25.12.18 12:01
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>А cppreference определяет)


Ну это типа свидетелей Иеговы, которые рассказывают, что написано в Библии. А правильно рассказывают или нет — хочешь верь, хочешь проверь.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 25.12.2018 12:13 rg45 . Предыдущая версия .
Re[49]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 26.12.18 16:40
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, N. I., Вы писали:


NI>>>>В последнее время плюсами я пользуюсь довольно редко и интерес к ним у меня уже совсем нет тот, что раньше.

R>>>С чем это связано? Если не секрет.
NI>>Надоели

R>Просто надоели, или, может, появились более интересные альтернативы?


А есть другой язык, похожий на С++ тем, что есть объекты на стеке и соответственно lvalue/rvalue?
Re[32]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 26.12.18 16:48
Оценка:
Здравствуйте, σ, Вы писали:

σ>Этот пункт чисто технический. Нужен для упрощения написания стандарта. В некоторых местах возникают выражения, для которых проще представить, что у них может быть ссылочный тип и ввести это правило в одном месте, чем каждый раз применять его в 10 местах.

σ>Например, проще сказать, что "id-expression имеет тип переменной, которую именует" (и тогда тип выражения как бы может быть ссылкой, если переменная — ссылка), чем "если id-expression обозначает переменную с не-ссылочным типом T, то тип выражения T; если с ссылочным — то тип, на который ссылается ссылка".

σ>Короче, "реально" выражений с ссылочным типом нет.


Очень большая у вас дискуссия получилась и запутанная. Может кто-нибудь объяснить, почему нет выражений со ссылочным типом?

int& func();
int main() {
   func(); // а вот это не выражение со ссылочным типом?
}
Re[50]: Зачем плюс?
От: rg45 СССР  
Дата: 26.12.18 17:01
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>А есть другой язык, похожий на С++ тем, что есть объекты на стеке и соответственно lvalue/rvalue?


В полном объеме — вряд ли. Но отдельные элементы встречаются. Например, в C# все объекты простых типов, а также типов-значений (value types) создаются как раз на стеке (если оставить за скобками возможность специальной операции т.н. "боксинга"). И эти объекты можно передавать в функции с параметрами, объявленными при помощи ключевого слова ref, фактически являющиеся аналогами lvalue-ссылок в С++.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[51]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 26.12.18 17:09
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Максим Рогожин, Вы писали:


МР>>А есть другой язык, похожий на С++ тем, что есть объекты на стеке и соответственно lvalue/rvalue?


R>В полном объеме — вряд ли. Но отдельные элементы встречаются. Например, в C# все объекты простых типов, а также типов-значений (value types) создаются как раз на стеке (если оставить за скобками возможность специальной операции т.н. "боксинга"). И эти объекты можно передавать в функции с параметрами, объявленными при помощи ключевого слова ref, фактически являющиеся аналогами lvalue-ссылок в С++.


С простыми типами все просто — для них же move-семантика не нужна
Re[52]: Зачем плюс?
От: rg45 СССР  
Дата: 26.12.18 17:12
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>>>А есть другой язык, похожий на С++ тем, что есть объекты на стеке и соответственно lvalue/rvalue?


R>>В полном объеме — вряд ли. Но отдельные элементы встречаются. Например, в C# все объекты простых типов, а также типов-значений (value types) создаются как раз на стеке (если оставить за скобками возможность специальной операции т.н. "боксинга"). И эти объекты можно передавать в функции с параметрами, объявленными при помощи ключевого слова ref, фактически являющиеся аналогами lvalue-ссылок в С++.


МР>С простыми типами все просто — для них же move-семантика не нужна


Что-то я не успеваю за тобой. Вроде только что говорили про ссылки и их востребованность и тут, вдруг, возникает move-семантика, ни с того, ни с сего.

И кстати, к value-типам в С# относятся не только простые типы, но типы, определенные пользователем, при помощи ключевого слова struct (структуры).
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 26.12.2018 17:31 rg45 . Предыдущая версия . Еще …
Отредактировано 26.12.2018 17:15 rg45 . Предыдущая версия .
Re[53]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 26.12.18 19:00
Оценка:
Здравствуйте, rg45, Вы писали:

R>Что-то я не успеваю за тобой. Вроде только что говорили про ссылки и их востребованность и тут, вдруг, возникает move-семантика, ни с того, ни с сего.

Просто для меня разделение на lvalue/rvalue ссылки прочно ассоциируется с move-семантикой. До тех пор пока не было move-семантики про lvalue/rvalue ссылки и разговоров особо не было.

R>И кстати, к value-типам в С# относятся не только простые типы, но типы, определенные пользователем, при помощи ключевого слова struct (структуры).

Эти struct могут содержать ссылку на динамическую память?
Re[54]: Зачем плюс?
От: rg45 СССР  
Дата: 26.12.18 19:07
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

R>>И кстати, к value-типам в С# относятся не только простые типы, но типы, определенные пользователем, при помощи ключевого слова struct (структуры).

МР>Эти struct могут содержать ссылку на динамическую память?

Могут.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[26]: Зачем плюс?
От: B0FEE664  
Дата: 02.01.19 14:18
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

BFE>>
BFE>>void foo(int&& n){}

BFE>>int main()
BFE>>{
BFE>>    int n = 3;
BFE>>    foo(n);     // мы точно знаем, что у n тип int. ошибка компиляции.
BFE>>    foo(1 + n); // ошибки компиляции нет, значит результат вычисления (1 + n)  - не int.
BFE>>}
BFE>>

BFE>>Я полагаю, что результат вычисления имеет тип int&&. Почему это не так?

МР>Этот пример, мог бы быть аргументом если бы тип функции был БЕССЫЛОЧНЫМ. В случае бессылочных типов компилятор принимает решение подходит или нет аргумент на основании только лишь информации о типе. Но для ссылочных (lvalue, rvalue) типов еще ДОПОЛНИТЕЛЬНО учитывается информация о value category. Правильно?

То, что value category учитывается — это правильно, но value category — это характеристика выражения, а не его результата.

МР>Вообще похоже что система типов в С++ соостоит из трех очень разных категорий типов: объекты, ссылки, функции. Те аргументы которые верны для одной категории (объекты) не уже не будут верны для другой категории (ссылки). Вот это, как мне кажется и не учел, B0FEE664.


В каком смысле — не учёл? Этот пример демонстрирует тот факт, что у n и у результата 1 + n разные типы. У результата 1 + n ссылочный тип, а у n тип int. Проблема тут не в том, что есть разные категории типов, а в том, что типы могут преобразовываться друг в друга, поэтому иногда трудно отличить один тип от другого.
И каждый день — без права на ошибку...
Re[27]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 02.01.19 19:52
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>
BFE>>>void foo(int&& n){}

BFE>>>int main()
BFE>>>{
BFE>>>    int n = 3;
BFE>>>    foo(n);     // мы точно знаем, что у n тип int. ошибка компиляции.
BFE>>>    foo(1 + n); // ошибки компиляции нет, значит результат вычисления (1 + n)  - не int.
BFE>>>}
BFE>>>


BFE>В каком смысле — не учёл? Этот пример демонстрирует тот факт, что у n и у результата 1 + n разные типы.

Не демонстрирует. Этот пример демонстрирует, что выражение n и выражение 1 + n относятся к разным категориям выражений C++. Тип результата обоих выражений один и тот же — int.

Ты value categoty рассматриваешь как часть типа выражения — это не верно, value category это еще одна характеристика выражения, наряду с типом выражения.

выражение тип выражения категория выражения
n int lvalue
n+1 int prvalue
Твоя функция принимает одно выражение и не принимает другое не потому, что у них разный тип, а потому что категория разная.
Отредактировано 02.01.2019 20:08 Максим Рогожин . Предыдущая версия . Еще …
Отредактировано 02.01.2019 20:02 Максим Рогожин . Предыдущая версия .
Re[28]: Зачем плюс?
От: B0FEE664  
Дата: 02.01.19 22:16
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

BFE>>В каком смысле — не учёл? Этот пример демонстрирует тот факт, что у n и у результата 1 + n разные типы.

МР>Не демонстрирует. Этот пример демонстрирует, что выражение n и выражение 1 + n относятся к разным категориям выражений C++. Тип результата обоих выражений один и тот же — int.
Допустим, что для int это так. Почему для пользовательских типов это иначе?

МР>Твоя функция принимает одно выражение и не принимает другое не потому, что у них разный тип, а потому что категория разная.

Если две сущности в одинаковых условиях ведут себя по разному, значит у них разный тип. Категория выражения — это вообще про другое.
И каждый день — без права на ошибку...
Re[29]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 03.01.19 15:37
Оценка:
Здравствуйте, B0FEE664, Вы писали:


BFE>Допустим, что для int это так. Почему для пользовательских типов это иначе?

Замени в своем примере int на пользовательский тип и убедишься, что получаются тот же результат)

BFE>Если две сущности в одинаковых условиях ведут себя по разному, значит у них разный тип.

Не верно это. Ты же сам в предыдущем сообщении согласился, что value category еще учитывается.
Re[30]: Зачем плюс?
От: B0FEE664  
Дата: 03.01.19 17:10
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

BFE>>Допустим, что для int это так. Почему для пользовательских типов это иначе?

МР>Замени в своем примере int на пользовательский тип и убедишься, что получаются тот же результат)

Разумеется я получу тот же результат, но для объектов можно пойти дальше и точно узнать тип самого объекта, а не его преобразование к типу параметра функции:

#include <iostream>

struct A
{
  void WhoAmI() &&
  {
      std::cout << "I am rvalue reference\n";
  }

  void WhoAmI() const &&
  {
      std::cout << "I am const rvalue reference\n";
  }
    
};


A operator+(A a1, A a2)
{
  return {};
}

int main()
{
  A a;
//  a.WhoAmI(); // error
  
  A& ra = a;
//  ra.WhoAmI(); // error
  
  (a + a).WhoAmI(); // ok

  return 0;
}


https://ideone.com/cJJQj4

Таким образом мы точно знаем, что (a + a) — это rvalue reference на A. Из того, что код не компилируется для a.WhoAmI() и не компилируется для ra.WhoAmI() мы выводим, что результат (a + a) не может быть типа A, он типа A&&. Я полагаю это достаточным основанием, чтобы считать, что 1 + n имеет тип int&&, а не int.

BFE>>Если две сущности в одинаковых условиях ведут себя по разному, значит у них разный тип.

МР>Не верно это. Ты же сам в предыдущем сообщении согласился, что value category еще учитывается.
Я согласился, что value category учитывается для выражений, но вопрос не про категорию выражения, а про результат выражения.
И каждый день — без права на ошибку...
Re[31]: Зачем плюс?
От: Максим Рогожин Россия  
Дата: 05.01.19 20:42
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Из того, что код не компилируется для a.WhoAmI() и не компилируется для ra.WhoAmI() мы выводим, что результат (a + a) не может быть типа A, он типа A&&.

А почему не вывести из этого, то что (a + a) относится к другой категории выражений и из-за этого ошибки компиляции возникают?

BFE>Я согласился, что value category учитывается для выражений, но вопрос не про категорию выражения, а про результат выражения.

Повторю — ты по моему считаешь, категорию выражения частью типа.
Re[54]: Зачем плюс?
От: σ  
Дата: 06.01.19 10:01
Оценка:
Эта хрень про регистры была добавлена вместе с guaranteed copy elision.
Что-то я это только сейчас заметил.
Re[44]: Зачем плюс?
От: σ  
Дата: 07.01.19 14:45
Оценка:
σ>>>>Будет unsigned int prvalue с отрицательным значением типа signed int.
NI>>>Я, конечно, понимаю, что некоторые вещи в правилах C++ расходятся со здравым смыслом, но не до такой же степени. Тип значения prvalue никак не может отличаться от типа prvalue.
σ>>Для указателей точно может. Вводя http://wg21.link/p0137 хотели, нет, жаждали, чтобы такое стало возможным.
σ>>Побочным эффектом явилось, например, то, что результатом char или unsigned int prvalue может быть значение типа int.

NI>Я сильно сомневаюсь, что задумка была именно такой, в противном случае те, кто это придумывал, совсем больны на голову. Кроме того, такая интерпретация правил в реале не имеет предсказательной силы.


NI>
#include <cstdint>
NI>#include <iostream>

NI>int main()
NI>{
NI>    std::int8_t x = -1;
NI>    std::cout << short(reinterpret_cast<std::uint8_t &>(x)) << std::endl;
NI>}

NI>Будь по-твоему, данная программа должна выводить -1, т.к. преобразование в short целочисленного значения, которое может быть представлено в short, оставляется без изменений. Попробуй найти хоть одну реализацию, дающую такой вывод.

Я слегка погорячился насчёт unsigned int prvalue с отрицательным значением signed int. Там будет неопределённое поведение.
В твоём примере кода тоже неопределённое поведение, причём об этом в стандарте сказано явно. Во всех стандартах, от C++98/03 до C++17.

C++98 и C++11
[expr.reinterpret.cast]/10 (/11 в C++11):
An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer
to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a
reference cast reinterpret_cast<T&>(x) has the same effect as the conversion
*reinterpret_cast<T*>(&x) with the built-in & and * operators. The result is an lvalue that refers
to the same object as the source lvalue, but with a different type.

[conv.lval]/1:
An lvalue (3.10) of a non-function, non-array type T can be converted to an rvalue. If T is an incomplete
type, a program that necessitates this conversion is ill-formed. If the object to which the lvalue refers is not
an object of type T
and is not an object of a type derived from T, or if the object is uninitialized, a program
that necessitates this conversion has undefined behavior.


lvalue типа uint8_t ссылается на объект типа int8_t → UB при lvalue-to-rvalue conversion

В C++98/03 и 11 UB всегда. В следующих стандартах UB зависит от значения объекта. А именно
C++14 и C++17
[expr.reinterpret.cast]/11 без изменений:
The result refers to the same object as the source glvalue, but with the specified type.
Из [conv.lval]/1 исчезло упоминание об UB.
A glvalue of a non-function, non-array type T can be converted to a prvalue. If T is an incomplete type, a program that necessitates this conversion is ill-formed. If T is a non-class type, the type of the prvalue is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.
[conv.lval]/(2.6) (/(3.4) в C++17):
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.

Я тыкал в последнее правило утверждая, что результатом будет то-то и то-то и это определённое поведение. Но надо обратить внимание на последнее предложение в [conv.lval]/1 и на [expr]/4:
If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

L-to-R, применённый к reinterpret_cast<std::uint8_t &>(x) имеет тип uint8_t, но значение, которое является результатом этого выражения — -1 (the value contained in the object indicated by the glvalue) — is not in the range of representable values for its type. Следовательно, the behavior is undefined.

Эти рассуждения справедливы и для unsigned int prvalue, которое получилось преобразованием lvalue, ссылавшимся на signed int с отрицательным значением. И для попытки читать из переменной с типом int через char glvalue значения, не влезающие в char.
Отредактировано 07.01.2019 14:50 σ . Предыдущая версия .
Re[43]: Зачем плюс?
От: B0FEE664  
Дата: 07.01.19 16:26
Оценка:
Здравствуйте, σ, Вы писали:

NI>>Стандартизаторы о такой практике наверняка знали, потому и попытались отразить в правилах возможность её применения, вот только сделать это уму у них пороху не хватило.

σ>В стандарте C написано https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7
σ> When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object.
σ>В стандарте C++ такого нет и вывести это ниоткуда нельзя.

Ну как же нет?! А это что?:

Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies.

И каждый день — без права на ошибку...
Re[44]: Зачем плюс?
От: σ  
Дата: 07.01.19 16:28
Оценка:
NI>>>Стандартизаторы о такой практике наверняка знали, потому и попытались отразить в правилах возможность её применения, вот только сделать это уму у них пороху не хватило.
σ>>В стандарте C написано https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7
σ>> When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object.
σ>>В стандарте C++ такого нет и вывести это ниоткуда нельзя.

BFE>Ну как же нет?! А это что?:

BFE>

BFE>Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies.


Тут не сказано, что каст к указателю на char даёт указатель на первый байт.
Re[45]: Зачем плюс?
От: B0FEE664  
Дата: 07.01.19 17:03
Оценка:
Здравствуйте, σ, Вы писали:

NI>>>>Стандартизаторы о такой практике наверняка знали, потому и попытались отразить в правилах возможность её применения, вот только сделать это уму у них пороху не хватило.

σ>>>В стандарте C написано https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7
σ>>> When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object.
σ>>>В стандарте C++ такого нет и вывести это ниоткуда нельзя.

BFE>>Ну как же нет?! А это что?:

BFE>>

BFE>>Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies.


σ>Тут не сказано, что каст к указателю на char даёт указатель на первый байт.

Да, не сказано, но:
https://timsong-cpp.github.io/cppwp/n4659/basic.types#2
и
https://timsong-cpp.github.io/cppwp/n4659/basic.types#4
И посмотрите на сноску 45:

The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.

И каждый день — без права на ошибку...
Re[46]: Зачем плюс?
От: σ  
Дата: 07.01.19 17:16
Оценка:
BFE>

BFE>The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.

intent intent-ом, но если до C++17 ещё можно было разными демагогическими приёмами высосать из пальца то, что получится указатель на первый байт, в C++17 это уже невозможно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.