From fb9e7028a03f8a00fb928ff659dbaaa6056572fc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 15 Nov 2025 11:58:24 -0600 Subject: [PATCH 1/3] [core] Replace seq<>/gens<> with std::index_sequence for code clarity --- esphome/components/api/user_services.h | 10 +++++--- esphome/components/script/script.h | 12 ++++----- esphome/core/automation.h | 35 ++++++++++++++++++-------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/esphome/components/api/user_services.h b/esphome/components/api/user_services.h index 2a887fc52d..2f753dfc6c 100644 --- a/esphome/components/api/user_services.h +++ b/esphome/components/api/user_services.h @@ -51,13 +51,14 @@ template class UserServiceBase : public UserServiceDescriptor { return false; if (req.args.size() != sizeof...(Ts)) return false; - this->execute_(req.args, typename gens::type()); + this->execute_(req.args, std::make_index_sequence{}); return true; } protected: virtual void execute(Ts... x) = 0; - template void execute_(const ArgsContainer &args, seq type) { + template + void execute_(const ArgsContainer &args, std::index_sequence type) { this->execute((get_execute_arg_value(args[S]))...); } @@ -95,13 +96,14 @@ template class UserServiceDynamic : public UserServiceDescriptor return false; if (req.args.size() != sizeof...(Ts)) return false; - this->execute_(req.args, typename gens::type()); + this->execute_(req.args, std::make_index_sequence{}); return true; } protected: virtual void execute(Ts... x) = 0; - template void execute_(const ArgsContainer &args, seq type) { + template + void execute_(const ArgsContainer &args, std::index_sequence type) { this->execute((get_execute_arg_value(args[S]))...); } diff --git a/esphome/components/script/script.h b/esphome/components/script/script.h index 51cece01e4..ec0a8f03ce 100644 --- a/esphome/components/script/script.h +++ b/esphome/components/script/script.h @@ -46,14 +46,14 @@ template class Script : public ScriptLogger, public Trigger &tuple) { - this->execute_tuple_(tuple, typename gens::type()); + this->execute_tuple_(tuple, std::make_index_sequence{}); } // Internal function to give scripts readable names. void set_name(const LogString *name) { name_ = name; } protected: - template void execute_tuple_(const std::tuple &tuple, seq /*unused*/) { + template void execute_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { this->execute(std::get(tuple)...); } @@ -157,7 +157,7 @@ template class QueueingScript : public Script, public Com const size_t queue_capacity = static_cast(this->max_runs_ - 1); auto tuple_ptr = std::move(this->var_queue_[this->queue_front_]); this->queue_front_ = (this->queue_front_ + 1) % queue_capacity; - this->trigger_tuple_(*tuple_ptr, typename gens::type()); + this->trigger_tuple_(*tuple_ptr, std::make_index_sequence{}); } } @@ -174,7 +174,7 @@ template class QueueingScript : public Script, public Com } } - template void trigger_tuple_(const std::tuple &tuple, seq /*unused*/) { + template void trigger_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { this->trigger(std::get(tuple)...); } @@ -305,7 +305,7 @@ template class ScriptWaitAction : public Action, while (!this->param_queue_.empty()) { auto ¶ms = this->param_queue_.front(); - this->play_next_tuple_(params, typename gens::type()); + this->play_next_tuple_(params, std::make_index_sequence{}); this->param_queue_.pop_front(); } // Queue is now empty - disable loop until next play_complex @@ -321,7 +321,7 @@ template class ScriptWaitAction : public Action, } protected: - template void play_next_tuple_(const std::tuple &tuple, seq /*unused*/) { + template void play_next_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { this->play_next_(std::get(tuple)...); } diff --git a/esphome/core/automation.h b/esphome/core/automation.h index 33e08c9c1c..af57e5b760 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -11,10 +11,23 @@ namespace esphome { -// https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971 -template struct seq {}; // NOLINT -template struct gens : gens {}; // NOLINT -template struct gens<0, S...> { using type = seq; }; // NOLINT +// C++20 std::index_sequence is now used for tuple unpacking +// Legacy seq<>/gens<> pattern deprecated but kept for backwards compatibility +// Remove before 2026.6.0 +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +template struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq {}; +template +struct ESPDEPRECATED("Use std::make_index_sequence instead. Removed in 2026.6.0", "2025.12.0") gens + : gens {}; +template struct gens<0, S...> { using type = seq; }; + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif #define TEMPLATABLE_VALUE_(type, name) \ protected: \ @@ -152,11 +165,11 @@ template class Condition { /// Call check with a tuple of values as parameter. bool check_tuple(const std::tuple &tuple) { - return this->check_tuple_(tuple, typename gens::type()); + return this->check_tuple_(tuple, std::make_index_sequence{}); } protected: - template bool check_tuple_(const std::tuple &tuple, seq /*unused*/) { + template bool check_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { return this->check(std::get(tuple)...); } }; @@ -231,11 +244,11 @@ template class Action { } } } - template void play_next_tuple_(const std::tuple &tuple, seq /*unused*/) { + template void play_next_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { this->play_next_(std::get(tuple)...); } void play_next_tuple_(const std::tuple &tuple) { - this->play_next_tuple_(tuple, typename gens::type()); + this->play_next_tuple_(tuple, std::make_index_sequence{}); } virtual void stop() {} @@ -277,7 +290,9 @@ template class ActionList { if (this->actions_begin_ != nullptr) this->actions_begin_->play_complex(x...); } - void play_tuple(const std::tuple &tuple) { this->play_tuple_(tuple, typename gens::type()); } + void play_tuple(const std::tuple &tuple) { + this->play_tuple_(tuple, std::make_index_sequence{}); + } void stop() { if (this->actions_begin_ != nullptr) this->actions_begin_->stop_complex(); @@ -298,7 +313,7 @@ template class ActionList { } protected: - template void play_tuple_(const std::tuple &tuple, seq /*unused*/) { + template void play_tuple_(const std::tuple &tuple, std::index_sequence /*unused*/) { this->play(std::get(tuple)...); } From b7f60133780da3e94e8cb1c1d02bf18cf65f2134 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 15 Nov 2025 12:04:02 -0600 Subject: [PATCH 2/3] [core] Replace seq<>/gens<> with std::index_sequence for code clarity --- esphome/core/automation.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index af57e5b760..6b5d77ab96 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -19,10 +19,13 @@ namespace esphome { #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif +// NOLINTNEXTLINE(readability-identifier-naming) template struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq {}; +// NOLINTNEXTLINE(readability-identifier-naming) template struct ESPDEPRECATED("Use std::make_index_sequence instead. Removed in 2026.6.0", "2025.12.0") gens : gens {}; +// NOLINTNEXTLINE(readability-identifier-naming) template struct gens<0, S...> { using type = seq; }; #if defined(__GNUC__) || defined(__clang__) From d7892f228920d365be433ba049ff34857fab004c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 15 Nov 2025 12:04:49 -0600 Subject: [PATCH 3/3] [core] Replace seq<>/gens<> with std::index_sequence for code clarity --- esphome/core/automation.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/core/automation.h b/esphome/core/automation.h index 6b5d77ab96..97c9e9c3cc 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -13,6 +13,7 @@ namespace esphome { // C++20 std::index_sequence is now used for tuple unpacking // Legacy seq<>/gens<> pattern deprecated but kept for backwards compatibility +// https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971 // Remove before 2026.6.0 #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push