Comments 26
Очень увлекательно, но есть тонкий момент - почему компилятор оставил в данных весь Canvas, хотя мог сохранить только Canvas[0][0] ?
MSVC в общем не славится своими оптимизациями. Может, GCC или clang бы соптимизировал в один Canvas[0][0]
@AskePitВы можете расшарить код на godbolt.org, чтобы проверить теорию? (clang trunk, по идее, все используемые вами фичи должен поддерживать точно; может, и gcc trunk, но не уверен)
Так, вот, кажется, рабочая ссылка https://godbolt.org/z/3o55Y7dv3
Я всегда теряюсь в интерфейсе Compiler Explorer и плохо в нем ориентируюсь, поэтому если сможете, расскажите потом о результатах :)
На самом деле меня тоже волновал этот вопрос) Но не вырезал и не вырезал, я пошел дальше с тем, что есть.
На самом деле, мне кажется, обмануть компилятор не так сложно в этом деле, поэтому если какой-то из них вырежет, то условный volatile
или std::cout
может исправить ситуацию
Вообще константа должна быть помещена в rodata только в том случае, если где-то в коде необходим её адрес, то есть MSVC, судя по всему, перевёл Canvas[0][0] в *(*(Canvas + 0) + 0), заметил в выражении использование адреса константы и поместил её в бинарник вместо того, чтобы сразу подставить в return true, но это лишь предположение
Прикольная история, мне такое нравится, сам помешан на constexpr немного
C++26
#include <cstddef>
template <size_t N, size_t M>
class Field {
static constexpr size_t SIZE = N * (M + 1);
char s[SIZE];
consteval char& _c(size_t i, size_t j) {
return s[(M + 1) * i + j];
}
public:
consteval Field() {
for (size_t i = 0; i < N; ++i) {
_c(i, 0) = '\n';
}
}
consteval char& c(size_t i, size_t j) {
return _c(i, j + 1);
}
consteval size_t size() {
return SIZE;
}
consteval const char* data() {
return s;
}
};
const size_t N = 16;
const size_t M = 16;
consteval auto message() {
Field<N, M> f;
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
f.c(i, j) = (i + j) % 4 ? '_' : '@';
}
}
return f;
}
int main() {
static_assert(false, message());
}
<source>: In function 'int main()':
<source>:49:19: error: static assertion failed:
@___@___@___@___
___@___@___@___@
__@___@___@___@_
_@___@___@___@__
@___@___@___@___
___@___@___@___@
__@___@___@___@_
_@___@___@___@__
@___@___@___@___
___@___@___@___@
__@___@___@___@_
_@___@___@___@__
@___@___@___@___
___@___@___@___@
__@___@___@___@_
_@___@___@___@__
49 | static_assert(false, message());
| ^~~~~
Не компилируется — не значит «не работает» :)
Вот то же самое хотел сказать. Правда, думал, как бы заставить компилятор человекочитаемую ошибку вывести, а до кастомного сообщения в static_assert, приводимого к char*, фантазии не хватило.
Ах да, это C++26. %-/
Там немного сложнее: в C++26 добавлена перегрузка для static_assert
, позволяющая передать user-generated сообщение. До этого можно было передать только литерал. Однако ассерт ожидает не const char*
, а объект с методами data()
и size()
. То есть, фактически, можно напрямую скормить ему std::vector<char>
или std::string
, но посимвольная конкатенация для строки немного медленно работает на большом цикле.
Вот, наговнокодил на С++20
https://gcc.godbolt.org/z/zTPGnEfzo
Вкратце
struct field { char xxx[Y][X]; };
// заполняем весь массив символами . и @
constexpr field get_my_field() { ..... }
template<field f> void bar() = delete;
int main() {
bar< get_my_field() >();
}
только потом надо будет распарсить выхлоп
<source>:70:26: error: use of deleted function 'void bar() [with field f = field{char [16][16]{
"...............",
"...............",
"...............",
"....@..........",
"..@.@..........",
"...@@..........",
"...............",
"...............",
"...............",
"...............",
"...............",
"...............",
"...............",
"...............",
"...............",
"..............."
}}]'
В порядке оффтопа (но не совсем). Некогда на Спеке был прорывной редактор/макроассемблер Tasm 4 (минорную версию забыл) за авторством Rst7. И там на макросах был написан пример - питончик, в который можно было играть, запустив компиляцию (т.е. это был полноценный compile-time). Не помню, как именно это было реализовано, но на тот момент это здорово так впечатляло.
Статья понравилась, жалко у меня не хватает кармы, чтобы повысить вам карму.
Узнал немного нового о compile time. Даже появилась идея, как возможно можно решить одну старую задумку, которая у меня до этого не получалась.
Когда-то давно тоже делал игру в жизнь, но с возможностью менять правила жизни мира в процессе выполнения.
П.С. Спасибо за статью)
В C++ уже больше 10 лет существует
constexpr
, который позволяет программисту ушло возложить часть вычислений на компилятор. В свое время это взорвало мне мозг, ведь компилятор может посчитать какие-то достаточно сложные вещи еще до запуска программы!
У Анатолия Воробья весной был конкурс, победитель которого как раз использовал этот подход. Программа компилировалась 6 секунд, но зато результат выдавала мгновенно, заведомо опередив всех остальных участников :)
https://avva.livejournal.com/3657269.html
Очень классный пост, даже набрался смелости немного дополнить код: https://godbolt.org/z/z5Y5ban5c. Суть крайне проста - с помощью рекурсии собираем матрицу из "прожитых" циклов и компилируем и вытаскиваем не по одной за раз, а сразу несколько, в зависимости от глубины. Мой msvc22 и gcc годболта выдают лучший результат при глубине <32, около 12 циклов в секунду
Помним — мы на Windows, и наиболее логичный компилятор, который нам доступен — это компилятор, который использует Visual Studio — Microsoft Visual C++ или MSVC.
А clang
на Windows разве не работает?
Более того, поставляется вместе со студией: https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-170#configure-a-windows-project-to-use-clang-tools
Работает
Прочитал от корки до корки, интересно, спасибо!
Афтор жжет! Безумно интересно и читается на одном дыхании. Спасибо!
Просто оставлю это здесь как родственную по духу статью.
В своем подходе автор-таки запускает exe, но лишь с целью отрендерить один кадр в файл. Луп крутит bash, а все действо происходит на Linux и компилируется g++. Из занятного - баш ловит ввод пользователя и передает его в g++ в качестве макро-definition
constexpr Game of Life