Встраивание продолжений времени компиляции C++

Я пытаюсь встроить следующий код C++:

    __attribute__((always_inline)) static void inline compose(const char* s, std::function<void(const char *)> f) {
       std::cout << s << std::endl;
       f(s);
   }

   // --------------- Main ---------------
   int main() {
       // Nest three things
       compose("hello world", [](const char *s) {
           compose("hello again", [](const char *s) {
               compose("hello third time", [](const char *s) {
                   return;
               });
           });
       });

       return 0;
   }

Здесь мои продолжения относятся к типу std::function<void(const char*)>, и от компилятора с опцией always_inline я хотел преобразовать его в один сайт вызова, который выглядит следующим образом:

// --------------- Main ---------------
   int main() {
       // Nest three things
       std::cout << "hello world" << std::endl;
       std::cout << "hello again" << std::endl;
       std::cout << "hello third time" << std::endl;
       return 0;
   }

Можно ли сделать это во время компиляции? Я думаю, что компилятор не может сделать это автоматически, но я думал, что препроцессор может, с constexpr и C++ 17.

Пометка compose как constexpr, что было бы очевидным решением, не работает, я попытался добавить constexpr к лямбдам, но безрезультатно.

rausted 08.06.2018 01:09

Откуда вы знаете, что компилятор не может автоматически оптимизировать ваш код продолжения до производительности, эквивалентной второй версии? Вы пробовали Godbolt?

jcai 08.06.2018 01:10

Я использую llvm и только что наблюдал ИК. Я не знаком с Godbolt.

rausted 08.06.2018 01:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
35
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Clang неплохо его оптимизирует. Использование std::function<> создает лишь небольшие накладные расходы, связанные со стиранием типа:

Стиль продолжения: https://godbolt.org/g/FxHSnV

Прямой стиль: https://godbolt.org/g/N1b8QC

Я использовал dummy_write(), чтобы избежать сложной сборки, созданной с помощью iostream и std::cout.

Стирание этого типа можно устранить, создав шаблон compose вместо использования std::function: https://godbolt.org/g/7QceN6

template<typename Func>
__attribute__((always_inline))
static void inline compose(const char* s, Func f) {
    dummy_write(s);
    f(s);
}

Отличное использование шаблонов, спасибо! Просто любопытно, почему в сборке стиля продолжения четыре вызова dummy_write?

rausted 08.06.2018 01:44

Четвертый dummy_write, по-видимому, является частью метода _M_invoke(), связанного с реализацией std::function. На самом деле он не вызывается в main(), но не оптимизирован. Неоптимизированное использование std::function, скорее всего, вызовет _M_invoke().

jcai 08.06.2018 01:58

Спасибо за дальнейшие объяснения!

rausted 08.06.2018 02:05

Другие вопросы по теме