занятно: constexpr + mutable
От: Sm0ke Россия ksi
Дата: 08.09.23 22:12
Оценка: 3 (1) -1 :)
constexpr + mutable (можно менять значение compile time константы)

Узнал об этом из этого видео:
  yt
https://www.youtube.com/watch?v=67DenIV45xY

И решил проверить: https://godbolt.org/z/r174GdMn9
#include <iostream>

struct t_const_mut
{
  // data
  mutable int
  value;

  constexpr int
  get() const
  { return ++this->value; }
};

constexpr const t_const_mut
g_obj{0};

int main()
{
  std::cout
  << g_obj.get() << ' '
  << g_obj.get() << '\n';
  
  return 0;
}


Результат:

Program returned: 0
1 2


Пока не придумал как это можно использовать. Просто занятный факт.

p/s gblt
При попытке вызвать t_const_mut::get() в consteval контексте компилятор от vs выдаёт Internal compiler error.
В то время как clang и gcc этого делать не позволяет, ссылаясь на чтение mutable мембера в compile-time. (или на изменение внешнего объекта, видимого за пределами метода)
Отредактировано 08.09.2023 22:22 Sm0ke . Предыдущая версия . Еще …
Отредактировано 08.09.2023 22:17 Sm0ke . Предыдущая версия .
Отредактировано 08.09.2023 22:14 Sm0ke . Предыдущая версия .
Re: занятно: constexpr + mutable
От: YuriV  
Дата: 09.09.23 07:48
Оценка: +3
Здравствуйте, Sm0ke, Вы писали:

S>constexpr + mutable (можно менять значение compile time константы)



S>Пока не придумал как это можно использовать. Просто занятный факт.


Что тут занятного ? Констэкспр перестал вычисляться в компайлтайм и стал вычисляться в рантайм. Так и было задумано. Мьютабл и констэкспр никак не связанные вещи.

S>p/s gblt

S>При попытке вызвать t_const_mut::get() в consteval контексте компилятор от vs выдаёт Internal compiler error.
S>В то время как clang и gcc этого делать не позволяет, ссылаясь на чтение mutable мембера в compile-time. (или на изменение внешнего объекта, видимого за пределами метода)

И это было задумано. Констевал требует возможности вычисления в компайл-тайм.
Re[2]: занятно: constexpr + mutable
От: Sm0ke Россия ksi
Дата: 09.09.23 10:43
Оценка:
Здравствуйте, YuriV, Вы писали:

YV>Что тут занятного ? Констэкспр перестал вычисляться в компайлтайм и стал вычисляться в рантайм. Так и было задумано. Мьютабл и констэкспр никак не связанные вещи.


В рантайм Меняется состояние constexpr константы.
Re[3]: занятно: constexpr + mutable
От: reversecode google
Дата: 09.09.23 11:09
Оценка:
так она ж mutable
Re[4]: занятно: constexpr + mutable
От: vopl Россия  
Дата: 09.09.23 11:15
Оценка:
Здравствуйте, reversecode, Вы писали:

R>так она ж mutable


mutable действует для анулирования const, про constexpr-объекты там речь вроде не идет, вот и возникает удивление. Попутались const и constexpr
Re[5]: занятно: constexpr + mutable
От: reversecode google
Дата: 09.09.23 11:19
Оценка:
constexpr который свершился или который не получился и компилер дальше пошел по обычным правилам ?
Re[6]: занятно: constexpr + mutable
От: vopl Россия  
Дата: 09.09.23 11:46
Оценка:
Здравствуйте, reversecode, Вы писали:

R>constexpr который свершился или который не получился и компилер дальше пошел по обычным правилам ?


Нет. Свершился или не получился — это про другое, это когда функция объявляется constexpr и вот непосредственно ее код то ли можно исполнить во время компиляции то ли нет. В текущем топике речь идет не об этом, но о constexpr переменных/объектах.

Судя по всему, дело обстоит так
https://timsong-cpp.github.io/cppwp/dcl.constexpr#6.sentence-1
Объект, задекларированный со спецификатором constexpr автоматически является const. Следовательно, поведение mutable для членов constexpr-объекта эквивалентно таковому для const-объекта https://timsong-cpp.github.io/cppwp/dcl.stc#9 .
Отредактировано 09.09.2023 11:54 vopl . Предыдущая версия . Еще …
Отредактировано 09.09.2023 11:52 vopl . Предыдущая версия .
Отредактировано 09.09.2023 11:47 vopl . Предыдущая версия .
Re[3]: занятно: constexpr + mutable
От: YuriV  
Дата: 09.09.23 19:21
Оценка: +1 -1
Здравствуйте, Sm0ke, Вы писали:

S>Здравствуйте, YuriV, Вы писали:


YV>>Что тут занятного ? Констэкспр перестал вычисляться в компайлтайм и стал вычисляться в рантайм. Так и было задумано. Мьютабл и констэкспр никак не связанные вещи.


S>В рантайм Меняется состояние constexpr константы.

constexpr говорит лишь о том, что компилятор сначала может попытаться вычислить значение выражение в компайл-тайм и если по каким-то причинам не может, то забывает о constexpr, неважно что это объявление метода или объекта. Выражение становиться просто константным, а мьютабл вы сами написали в классе. Так что ничего занятного.
Re[4]: занятно: constexpr + mutable
От: vopl Россия  
Дата: 10.09.23 09:10
Оценка:
Здравствуйте, YuriV, Вы писали:

YV>Здравствуйте, Sm0ke, Вы писали:


S>>Здравствуйте, YuriV, Вы писали:


YV>>>Что тут занятного ? Констэкспр перестал вычисляться в компайлтайм и стал вычисляться в рантайм. Так и было задумано. Мьютабл и констэкспр никак не связанные вещи.


S>>В рантайм Меняется состояние constexpr константы.

YV>constexpr говорит лишь о том, что компилятор сначала может попытаться вычислить значение выражение в компайл-тайм и если по каким-то причинам не может, то забывает о constexpr, неважно что это объявление метода или объекта. Выражение становиться просто константным, а мьютабл вы сами написали в классе. Так что ничего занятного.

В случае объявления объекта со спецификатором constexpr все немного не так. Такой объект инициализируется константным выражением и никак иначе. Он не может "несмочь" и перейти в рантайм. Возвращаясь к исходной теме можно сказать что далее, такой объект постулируется юзабельным в константном выражении, только за исключением mutable. С другой стороны mutable разрешено использовать в рантайм потому что constexpr-объект является const, а для const мутабельнсть анулирует const.
Re[4]: constexpr + mutable
От: Sm0ke Россия ksi
Дата: 10.09.23 11:34
Оценка:
Здравствуйте, YuriV, Вы писали:

S>>В рантайм Меняется состояние constexpr константы.

YV>constexpr говорит лишь о том, что компилятор сначала может попытаться вычислить значение выражение в компайл-тайм и если по каким-то причинам не может, то забывает о constexpr, неважно что это объявление метода или объекта. Выражение становиться просто константным, а мьютабл вы сами написали в классе. Так что ничего занятного.

constexpr у метода прдоставляет возможность вызвать этот метод не только в run-time, но и в compile-time.
Однако эту возможность constexpr не гарантирует.
Компилятор решает исходя из контекста вызова — является ли этот вызов compile-time вычислением, или run-time вычислением.

  например
enum {
n_value = some_funct() // compile-time call
};


В случае compile-time происходит проверка допустимости выражения (и в вызове может быть отказано).

В коде моего исходного поста ...

#include <iostream>

struct t_const_mut
{
  // data
  mutable int
  value;

  constexpr int
  get() const
  { return ++this->value; }
};

constexpr const t_const_mut // и constexpr и const
g_obj{0}; // глобальная ячейка

int main()
{
  std::cout
  << g_obj.get() << ' '
  << g_obj.get() << '\n';
  
  return 0;
}


... метод get() const меняет mutable свойство того объекта, который лежит за пределами body этого метода.
И компилятор запрещает вызов этого метода в compile-time, несмотря на то что метод является constexpr.
пруф: https://godbolt.org/z/vqvrf95PM (другой пример)
  clang

<source>:18:5: error: non-type template argument is not a constant expression
TAG<g_obj.get()> g_tag;
^~~~~~~~~~~
<source>:11:12: note: a constant expression cannot modify an object that is visible outside that expression
{ return ++this->value; }
^
<source>:18:11: note: in call to '&g_obj->get()'
TAG<g_obj.get()> g_tag;
^
1 error generated.
Compiler returned: 1

#include <iostream>

struct t_const_mut
{
  // data
  mutable int
  value;

  constexpr int
  get() const
  { return ++this->value; }
};

constexpr const t_const_mut
g_obj{0};

template <int I> struct TAG {};
TAG<g_obj.get()> g_tag;

int main()
{
  std::cout
  << g_obj.get() << ' '
  << g_obj.get() << '\n';
  
  return 0;
}


Но даже если убрать инкремент, компилятор всё равно запретит (из-за чтения mutable у внешнего объекта).
пруф: https://godbolt.org/z/P3aq8n613 (ещё другой пример)
  clang

<source>:18:5: error: non-type template argument is not a constant expression
TAG<g_obj.get()> g_tag;
^~~~~~~~~~~
<source>:11:12: note: read of mutable member 'value' is not allowed in a constant expression
{ return this->value; }
^
<source>:18:11: note: in call to '&g_obj->get()'
TAG<g_obj.get()> g_tag;
^
<source>:7:3: note: declared here
value;
^
1 error generated.
Compiler returned: 1

#include <iostream>

struct t_const_mut
{
  // data
  mutable int
  value;

  constexpr int
  get() const
  { return this->value; } // без инкремента
};

constexpr const t_const_mut
g_obj{0};

template <int I> struct TAG {};
TAG<g_obj.get()> g_tag;

int main()
{
  std::cout
  << g_obj.get() << ' '
  << g_obj.get() << '\n';
  
  return 0;
}


А что если обращаться в методе get() к mutable свойству у локального объекта?
проверим: https://godbolt.org/z/nq3TT4zbr (пример с локальным объектом метода get)

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
1 1


Компилируется!

#include <iostream>

struct t_const_mut
{
  // data
  mutable int
  value;

  constexpr int
  get() const
  { t_const_mut v{}; return ++v.value; }
};

constexpr const t_const_mut
g_obj{0};

template <int I> struct TAG {};
TAG<g_obj.get()> g_tag;

int main()
{
  std::cout
  << g_obj.get() << ' '
  << g_obj.get() << '\n';
  
  return 0;
}
Отредактировано 10.09.2023 11:52 Sm0ke . Предыдущая версия . Еще …
Отредактировано 10.09.2023 11:48 Sm0ke . Предыдущая версия .
Отредактировано 10.09.2023 11:43 Sm0ke . Предыдущая версия .
Отредактировано 10.09.2023 11:42 Sm0ke . Предыдущая версия .
Отредактировано 10.09.2023 11:39 Sm0ke . Предыдущая версия .
Отредактировано 10.09.2023 11:37 Sm0ke . Предыдущая версия .
Re: занятно: constexpr + mutable
От: sergii.p  
Дата: 12.09.23 06:51
Оценка: -1
Здравствуйте, Sm0ke, Вы писали:

S>constexpr + mutable (можно менять значение compile time константы)


вот такое должно работать на gcc/msvc

constexpr auto l = []() mutable { return __COUNTER__; };

значение compile time константы не меняем, но constexpr + mutable
Re[2]: занятно: constexpr + mutable
От: vopl Россия  
Дата: 12.09.23 08:13
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>Здравствуйте, Sm0ke, Вы писали:


S>>constexpr + mutable (можно менять значение compile time константы)


SP>вот такое должно работать на gcc/msvc


SP>
SP>constexpr auto l = []() mutable { return __COUNTER__; };
SP>

SP>значение compile time константы не меняем, но constexpr + mutable

используемый тут спецификатор mutable не относится к состоянию объекта l
Re[3]: занятно: constexpr + mutable
От: sergii.p  
Дата: 12.09.23 08:31
Оценка:
Здравствуйте, vopl, Вы писали:

V>используемый тут спецификатор mutable не относится к состоянию объекта l


спасибо, кэп.
Re[4]: занятно: constexpr + mutable
От: vopl Россия  
Дата: 12.09.23 08:37
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>Здравствуйте, vopl, Вы писали:


V>>используемый тут спецификатор mutable не относится к состоянию объекта l


SP>спасибо, кэп.


На здоровье, конечно. Если для тебя это очевидно — зачем тогда говоришь что тут constexpr+mutable?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.