Pull to refresh

Comments 31

Сегодня мы поговорим о том, как constexprconsteval, и constinit позволяют реализовывать компиляцию на этапе выполнения.

constexpr делает возможным вычисление значений переменных во время компиляции.

Так на этапе выполнения или во время компиляции, или это (неожиданно!) одно и то же?

Сдается мне, заголовок

Компиляция на этапе выполнения в C++ ...

не соответствует содержанию.

Хорошее замечание. Но здесь стоит отметить, что такой расклад вполне возможен, если рассматривать общую картину, так как в некоторых языках программирования возможна докомпиляция при старте приложения.
Другой вопрос — насколько это относится непосредственно к C++.

так вот же написано:

Отличие consteval от его братца constexpr в том, что constexpr дает выбор: если что-то можно вычислить на этапе компиляции, отлично, но если нет — ну что ж, попробуем в рантайме.

или

constinit указывает, что переменная должна быть инициализирована во время старта программы, до входа в main()

по поводу

возможна докомпиляция при старте приложения

Да! Похоже это глобальная тенденция: статью не читаем, обсуждаем то, что сами придумаем примерно по теме.

Нет, я обсуждаю конкретно содержимое комментария. Специально отделяю общий случай и текущий.
Что в общем случае, без уточнения языка, докомпиляция в рантайме вполне возможна.
Однако в текущем случае, когда язык C++ и const(expr/eval/init), возникают вопросы. Может быть, у кого-то даже претензии, не важно.

Уточнение было адресовано, скорее, другим читателям, которые пока не понимают особенностей. Разъяснение причины возникновения вопросов к статье.

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

я исходил из того что автор сам себе противоречит, поэтому непонятно есть ли смысл анализировать то что он написал.

докомпиляция в рантайме вполне возможна

это что-то страшное - это надо компилятор с препроцессором и с линкером как библиотеки тащить, мне кажется это не реально. +вечная проблема с хидерами на С/С++ совсем не реально.

это что-то страшное - это надо компилятор с препроцессором и с линкером как библиотеки тащить, мне кажется это не реально. 

-lclang* -lLLVMMCJIT и вперёд )

мне кажется это не реально

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

в некоторых языках программирования возможна докомпиляция при старте приложения.

В некоторых языках возможна и кодогенерация во время исполнения, Expression в C# живой пример

Другой вопрос — насколько это относится непосредственно к C++

Простой ответ: нисколько. Ни один существующий стандарт С++ не предусматривает компиляции в runtime

Имхо, здесь перепутано с "вычислением на этапе компиляции".

Если не ошибаюсь, начиная с C++20, на этапе компиляции могут быть выполнены некоторые алгоритмы из STL. В каком-то смысле это можно назвать "выполнение на этапе компиляции", а здесь наоборот написано.

Может быть "вычисление на этапе компиляции", не?

Компиляция на этапе выполнения в С++??? Впервые вижу такой термин в плюсах ))) Есть стойкое ощущение, что статья требует серьезной доработки.

Компиляция на этапе выполнения? Нет ничего проще!

system("make all");

Передовой JIT-компилятор

system("g++ main.cpp -o main && ./main");

Дык ОТУС же - гарантия максимально низкого качества материала.

constinit указывает, что переменная должна быть инициализирована во время старта программы, до входа в main()

А когда инициализируются глобальные переменные без constinit и прочих явных спецификаторов?

Ну прежде всего конечно не "компиляция на этапе выполнения" а "выполнение на этапе компиляции":)

А вообще на мой взгляд все эти новые возможности C++ выглядят как-то костыльно. Если constexpr это вроде как просьба к компилятору, а не требование (по типу inline?) , то какие могут быть ошибки? Не получилось сделать во время компмляции - будет во время выполнения, или как?

Понятно что у кого-то возникла потребность использовать тот же код и для времени компиляции и для времени выполнения. Понятно что во время компиляции любой код не выполнить - есть ограничения. Но вот способ реализации этого в языке... странный. На мой взгляд было бы логичнее единственное ключевое слово с фигурными скобками, которое заставляло бы компилятор вычислять все содержимое блока во время компиляции - или выдавать ошибку. Зачем это привязали именно к объектам - непонятно.

которое заставляло бы компилятор вычислять все содержимое блока

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

Можно было сделать как в языке zig, ключевое слово comptime:

fn multiply(a: i64, b: i64) i64 {
    return a * b;
}

pub fn main() void {
    const len = comptime multiply(4, 5);
    const my_static_array: [len]u8 = undefined;
}

Интуитивно просто, привязка именно к выражению (фрагменту кода), а не к объекту.

А вообще и разрешить блокам возвращать значения не помешало бы, во многих языках блоки кода работают как выражения.

А вообще и разрешить блокам возвращать значения не помешало бы

Вместо { ... } пишите [&] { ... return whatever; }().

В gcc (в режиме C, не С++) есть интересное расширение позволяющее вставлять куски кода в выражение. Результатом такого блока является последнее вычисленное выражение.

Пример:

int x = 7;
while(x>1) {  
  printf("%d\n", 
    10 * ({ if(x%2) x=3*x+1; else x/=2; x;})
  );
}

В gcc вообще много интересных расширений. Вместо того чтобы придумывать всякую фигню, комитету по стандартизации для начала следовало бы просто взять и стандартизировать расширения С/С++ из gcc.

Справедливости ради, inline - это тоже не требование, а просьба. Если нет дополнительных ключевых слов (always_inline, __forceinline, etc...), то компилятор сам решает инлайнить или нет.

В современном C++ inline - это про объявление, а не про встраивания тела функции... В какой-то момент это ключевое слово поменяло семантику.

Справедливости ради, inline - это тоже не требование, а просьба

Да, я это и имел в виду (хотя фраза получилась неоднозначной, да). ИМХО, с точки зрения дизайна языка просьбы к компилятору вообще лучше оформлять не ключевыми словами, а какими-то атрибутами/аннотациями.

Если constexpr это вроде как просьба к компилятору, а не требование (по типу inline?)

Так Inline тоже уже давно не требование, попробуйте напрмер экспортировать такую функцию из .so или .dll

Так что если нужно создать constexpr вектор, который динамически изменяется во время компиляции - не выйдет.

Что тут подразумевается под "динамически изменяется"? Что ему можно сделать resize/shrink_to_fit? Это сделать можно.

Не понимаю, чего к статье столько комментариев о "низком качестве".

Если опустить оплошность в преамбуле и оставить сам материал, то получается приемлемый обзор фичи const(expr|eval|init).

Доработать, и будет прекрасно.

Получается, что, если функция fibonacci на этапе исполнения требовала 15 секунд на выполнение, то сделав ее consteval время компиляции возрастет на те же самые 15 секунд? Но на этапе исполнения трат уже не будет?

constinit LoggerConfig globalLoggerConfig{3, "/var/log/myapp.log"};

Не сработает, т.к. конструктор std::string (тип одного из элементов структуры LoggerConfig) динамически выделяет память.

"Компиляция на этапе выполнения" это скорее к джитам(jit) или языкам, которые открывают сам компилятор как встроенную библиотеку внутри языка, что не является случаем с++.

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

У вас в примере для consteval комментарий указывает объявление с его помощью переменной, а на самом деле вы используете constexpr.

Sign up to leave a comment.