[modernize] Unify VariadicEvaluate using C++17 std::apply

Change-Id: Iaf8ced8c2b937cb3c503e677adb96be32d6eace8
diff --git a/include/ceres/internal/variadic_evaluate.h b/include/ceres/internal/variadic_evaluate.h
index 61af6b2..eaf059b 100644
--- a/include/ceres/internal/variadic_evaluate.h
+++ b/include/ceres/internal/variadic_evaluate.h
@@ -33,7 +33,11 @@
 #ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
 #define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
 
+#include <algorithm>
+#include <array>
 #include <cstddef>
+#include <functional>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -42,51 +46,6 @@
 
 namespace ceres::internal {
 
-// For fixed size cost functors
-template <typename Functor, typename T, int... Indices>
-inline bool VariadicEvaluateImpl(const Functor& functor,
-                                 T const* const* input,
-                                 T* output,
-                                 std::false_type /*is_dynamic*/,
-                                 std::integer_sequence<int, Indices...>) {
-  static_assert(sizeof...(Indices) > 0,
-                "Invalid number of parameter blocks. At least one parameter "
-                "block must be specified.");
-  return functor(input[Indices]..., output);
-}
-
-// For dynamic sized cost functors
-template <typename Functor, typename T>
-inline bool VariadicEvaluateImpl(const Functor& functor,
-                                 T const* const* input,
-                                 T* output,
-                                 std::true_type /*is_dynamic*/,
-                                 std::integer_sequence<int>) {
-  return functor(input, output);
-}
-
-// For ceres cost functors (not ceres::CostFunction)
-template <typename ParameterDims, typename Functor, typename T>
-inline bool VariadicEvaluateImpl(const Functor& functor,
-                                 T const* const* input,
-                                 T* output,
-                                 const void* /* NOT USED */) {
-  using ParameterBlockIndices =
-      std::make_integer_sequence<int, ParameterDims::kNumParameterBlocks>;
-  using IsDynamic = std::integral_constant<bool, ParameterDims::kIsDynamic>;
-  return VariadicEvaluateImpl(
-      functor, input, output, IsDynamic(), ParameterBlockIndices());
-}
-
-// For ceres::CostFunction
-template <typename ParameterDims, typename Functor, typename T>
-inline bool VariadicEvaluateImpl(const Functor& functor,
-                                 T const* const* input,
-                                 T* output,
-                                 const CostFunction* /* NOT USED */) {
-  return functor.Evaluate(input, output, nullptr);
-}
-
 // Variadic evaluate is a helper function to evaluate ceres cost function or
 // functors using an input, output and the parameter dimensions. There are
 // several ways different possibilities:
@@ -103,7 +62,31 @@
 inline bool VariadicEvaluate(const Functor& functor,
                              T const* const* input,
                              T* output) {
-  return VariadicEvaluateImpl<ParameterDims>(functor, input, output, &functor);
+  if constexpr (std::is_base_of_v<CostFunction, Functor>) {
+    return functor.Evaluate(input, output, nullptr);
+  } else {
+    if constexpr (ParameterDims::kIsDynamic) {
+      return functor(input, output);
+    } else {
+      constexpr int kNumParameterBlocks = ParameterDims::kNumParameterBlocks;
+      static_assert(kNumParameterBlocks > 0,
+                    "Invalid number of parameter blocks. At least one "
+                    "parameter block must be specified.");
+
+      std::array<const T*, kNumParameterBlocks> parameter_blocks;
+      std::copy_n(input, kNumParameterBlocks, parameter_blocks.begin());
+      return std::apply(
+          [&functor, output](auto const*... blocks) {
+            static_assert(
+                std::is_invocable_v<const Functor&, decltype(blocks)..., T*>,
+                "The provided Functor's operator() signature does not match "
+                "the expected number of parameter blocks defined in "
+                "ParameterDims.");
+            return std::invoke(functor, blocks..., output);
+          },
+          parameter_blocks);
+    }
+  }
 }
 
 // When differentiating dynamically sized CostFunctions, VariadicEvaluate