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; }