From d277dc5ae9dfef86d61cadf78781dc77e7564613 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 7 Apr 2026 14:33:04 -1000 Subject: [PATCH 1/3] [lvgl][sensor] Remove std::move on trivially copyable TemplatableFn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clang-tidy flags std::move on trivially copyable types as no-op. TemplatableFn is a single function pointer — copy is equivalent. --- esphome/components/lvgl/lvgl_esphome.cpp | 2 +- esphome/components/sensor/filter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/lvgl/lvgl_esphome.cpp b/esphome/components/lvgl/lvgl_esphome.cpp index 2d27d2cd4d..56dc605dcc 100644 --- a/esphome/components/lvgl/lvgl_esphome.cpp +++ b/esphome/components/lvgl/lvgl_esphome.cpp @@ -317,7 +317,7 @@ void LvglComponent::flush_cb_(lv_display_t *disp_drv, const lv_area_t *area, uin lv_display_flush_ready(disp_drv); } -IdleTrigger::IdleTrigger(LvglComponent *parent, TemplatableFn timeout) : timeout_(std::move(timeout)) { +IdleTrigger::IdleTrigger(LvglComponent *parent, TemplatableFn timeout) : timeout_(timeout) { parent->add_on_idle_callback([this](uint32_t idle_time) { if (!this->is_idle_ && idle_time > this->timeout_.value()) { this->is_idle_ = true; diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index d1553e3cb5..fbac7d3535 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -213,12 +213,12 @@ optional LambdaFilter::new_value(float value) { } // OffsetFilter -OffsetFilter::OffsetFilter(TemplatableFn offset) : offset_(std::move(offset)) {} +OffsetFilter::OffsetFilter(TemplatableFn offset) : offset_(offset) {} optional OffsetFilter::new_value(float value) { return value + this->offset_.value(); } // MultiplyFilter -MultiplyFilter::MultiplyFilter(TemplatableFn multiplier) : multiplier_(std::move(multiplier)) {} +MultiplyFilter::MultiplyFilter(TemplatableFn multiplier) : multiplier_(multiplier) {} optional MultiplyFilter::new_value(float value) { return value * this->multiplier_.value(); } From 05011a28a0f2a5f1f9e433cfdfd5173fffdd5161 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 7 Apr 2026 14:35:22 -1000 Subject: [PATCH 2/3] [core] Support convertible return types in TemplatableFn via trampoline TemplatableFn now accepts stateless lambdas whose return type is convertible to T (e.g., int -> uint8_t). Uses a casting trampoline that reconstructs the stateless lambda via F{} (default-constructible in C++20). Also: - Remove std::move on trivially copyable TemplatableFn (clang-tidy) - Wrap http_request method via cg.templatable() --- esphome/core/automation.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index d286782293..fbe7224b70 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -41,10 +41,16 @@ template class TemplatableFn { public: TemplatableFn() = default; + // Exact return type match — direct function pointer storage template TemplatableFn(F f) requires std::convertible_to : f_(f) {} + // Convertible return type (e.g., int -> uint8_t) — casting trampoline. + // Stateless lambdas are default-constructible in C++20, so F{} recreates the lambda inside + // the trampoline without capturing. This compiles to the same code as a direct call + cast. template - TemplatableFn(F) requires std::invocable &&(!std::convertible_to) = delete; + TemplatableFn(F) requires(!std::convertible_to) && + std::invocable &&std::convertible_to, T> &&std::is_empty_v + &&std::default_initializable : f_([](X... x) -> T { return static_cast(F{}(x...)); }) {} bool has_value() const { return this->f_ != nullptr; } From 4cc6624cb009f1062da24696843d6ce15a3aaef5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 7 Apr 2026 14:37:54 -1000 Subject: [PATCH 3/3] [core] Emit deprecation warning on TemplatableFn return type mismatch --- esphome/core/automation.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index fbe7224b70..355968b284 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -47,8 +47,10 @@ template class TemplatableFn { // Convertible return type (e.g., int -> uint8_t) — casting trampoline. // Stateless lambdas are default-constructible in C++20, so F{} recreates the lambda inside // the trampoline without capturing. This compiles to the same code as a direct call + cast. + // Deprecated: codegen should use the correct output type to avoid the trampoline. template - TemplatableFn(F) requires(!std::convertible_to) && + [[deprecated("Lambda return type does not match TemplatableFn — use the correct type in " + "codegen")]] TemplatableFn(F) requires(!std::convertible_to) && std::invocable &&std::convertible_to, T> &&std::is_empty_v &&std::default_initializable : f_([](X... x) -> T { return static_cast(F{}(x...)); }) {}