Remove trailing zero parameter block sizes

This patch removes the use of trailing zeros in cost functions used in
unit tests as this will be an error once the sized cost function is
implemented using variadic templates.

Change-Id: I3e8a31b310ba7299fc6b1f012f540a3118cc7661
diff --git a/internal/ceres/evaluator_test.cc b/internal/ceres/evaluator_test.cc
index 79006f7..a0b28ee 100644
--- a/internal/ceres/evaluator_test.cc
+++ b/internal/ceres/evaluator_test.cc
@@ -55,12 +55,14 @@
 using std::vector;
 
 // TODO(keir): Consider pushing this into a common test utils file.
-template<int kFactor, int kNumResiduals,
-         int N0 = 0, int N1 = 0, int N2 = 0, bool kSucceeds = true>
+template <int kFactor, int kNumResiduals, int... Ns>
 class ParameterIgnoringCostFunction
-    : public SizedCostFunction<kNumResiduals, N0, N1, N2> {
-  typedef SizedCostFunction<kNumResiduals, N0, N1, N2> Base;
+    : public SizedCostFunction<kNumResiduals, Ns...> {
+  typedef SizedCostFunction<kNumResiduals, Ns...> Base;
+
  public:
+  ParameterIgnoringCostFunction(bool succeeds = true) : succeeds_(succeeds) {}
+
   virtual bool Evaluate(double const* const* parameters,
                         double* residuals,
                         double** jacobians) const {
@@ -91,8 +93,11 @@
         }
       }
     }
-    return kSucceeds;
+    return succeeds_;
   }
+
+ private:
+  bool succeeds_;
 };
 
 struct EvaluatorTestOptions {
@@ -112,7 +117,7 @@
     : public ::testing::TestWithParam<EvaluatorTestOptions> {
   Evaluator* CreateEvaluator(Program* program) {
     // This program is straight from the ProblemImpl, and so has no index/offset
-    // yet; compute it here as required by the evalutor implementations.
+    // yet; compute it here as required by the evaluator implementations.
     program->SetParameterOffsetsAndIndex();
 
     if (VLOG_IS_ON(1)) {
@@ -457,12 +462,12 @@
   problem.AddParameterBlock(z,  4);
 
   // f(x, y) in R^2
-  problem.AddResidualBlock(new ParameterIgnoringCostFunction<1, 2, 2, 3>,
+ problem.AddResidualBlock(new ParameterIgnoringCostFunction<1, 2, 2, 3>,
                            NULL,
                            x, y);
 
   // g(x, z) in R^3
-  problem.AddResidualBlock(new ParameterIgnoringCostFunction<2, 3, 2, 4>,
+ problem.AddResidualBlock(new ParameterIgnoringCostFunction<2, 3, 2, 4>,
                            NULL,
                            x, z);
 
@@ -526,7 +531,7 @@
 TEST_P(EvaluatorTest, EvaluatorAbortsForResidualsThatFailToEvaluate) {
   // Switch the return value to failure.
   problem.AddResidualBlock(
-      new ParameterIgnoringCostFunction<20, 3, 2, 3, 4, false>, NULL, x, y, z);
+      new ParameterIgnoringCostFunction<20, 3, 2, 3, 4>(false), NULL, x, y, z);
 
   // The values are ignored.
   double state[9];
diff --git a/internal/ceres/line_search_preprocessor_test.cc b/internal/ceres/line_search_preprocessor_test.cc
index d0a866b..301509c 100644
--- a/internal/ceres/line_search_preprocessor_test.cc
+++ b/internal/ceres/line_search_preprocessor_test.cc
@@ -105,8 +105,8 @@
   EXPECT_TRUE(preprocessor.Preprocess(options, &problem, &pp));
 }
 
-template<int kNumResiduals, int N1 = 0, int N2 = 0, int N3 = 0>
-class DummyCostFunction : public SizedCostFunction<kNumResiduals, N1, N2, N3> {
+template <int kNumResiduals, int... Ns>
+class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
diff --git a/internal/ceres/parameter_block_ordering_test.cc b/internal/ceres/parameter_block_ordering_test.cc
index 339e73b..ba61be6 100644
--- a/internal/ceres/parameter_block_ordering_test.cc
+++ b/internal/ceres/parameter_block_ordering_test.cc
@@ -51,8 +51,8 @@
 typedef Graph<ParameterBlock*> HessianGraph;
 typedef std::unordered_set<ParameterBlock*> VertexSet;
 
-template <int M, int N1 = 0, int N2 = 0, int N3 = 0>
-class DummyCostFunction: public SizedCostFunction<M, N1, N2, N3> {
+template <int M, int... Ns>
+class DummyCostFunction : public SizedCostFunction<M, Ns...> {
   virtual bool Evaluate(double const* const* parameters,
                         double* residuals,
                         double** jacobians) const {
diff --git a/internal/ceres/program_test.cc b/internal/ceres/program_test.cc
index 52eaa40..01bf233 100644
--- a/internal/ceres/program_test.cc
+++ b/internal/ceres/program_test.cc
@@ -35,9 +35,10 @@
 #include <memory>
 #include <vector>
 
-#include "ceres/sized_cost_function.h"
+#include "ceres/internal/integer_sequence_algorithm.h"
 #include "ceres/problem_impl.h"
 #include "ceres/residual_block.h"
+#include "ceres/sized_cost_function.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "gtest/gtest.h"
 
@@ -62,22 +63,23 @@
 };
 
 // Templated base class for the CostFunction signatures.
-template <int kNumResiduals, int N0, int N1, int N2>
-class MockCostFunctionBase : public
-SizedCostFunction<kNumResiduals, N0, N1, N2> {
+template <int kNumResiduals, int... Ns>
+class MockCostFunctionBase : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   virtual bool Evaluate(double const* const* parameters,
                         double* residuals,
                         double** jacobians) const {
+    const int kNumParameters = Sum<integer_sequence<int, Ns...>>::Value;
+
     for (int i = 0; i < kNumResiduals; ++i) {
-      residuals[i] = kNumResiduals +  N0 + N1 + N2;
+      residuals[i] = kNumResiduals + kNumParameters;
     }
     return true;
   }
 };
 
-class UnaryCostFunction : public MockCostFunctionBase<2, 1, 0, 0> {};
-class BinaryCostFunction : public MockCostFunctionBase<2, 1, 1, 0> {};
+class UnaryCostFunction : public MockCostFunctionBase<2, 1> {};
+class BinaryCostFunction : public MockCostFunctionBase<2, 1, 1> {};
 class TernaryCostFunction : public MockCostFunctionBase<2, 1, 1, 1> {};
 
 TEST(Program, RemoveFixedBlocksNothingConstant) {
@@ -247,14 +249,14 @@
   problem.AddParameterBlock(y, 3);
   problem.AddParameterBlock(&z, 1);
 
-  problem.AddResidualBlock(new MockCostFunctionBase<2, 2, 0, 0>(), NULL, x);
-  problem.AddResidualBlock(new MockCostFunctionBase<3, 1, 2, 0>(), NULL, &z, x);
-  problem.AddResidualBlock(new MockCostFunctionBase<4, 1, 3, 0>(), NULL, &z, y);
-  problem.AddResidualBlock(new MockCostFunctionBase<5, 1, 3, 0>(), NULL, &z, y);
-  problem.AddResidualBlock(new MockCostFunctionBase<1, 2, 1, 0>(), NULL, x, &z);
-  problem.AddResidualBlock(new MockCostFunctionBase<2, 1, 3, 0>(), NULL, &z, y);
-  problem.AddResidualBlock(new MockCostFunctionBase<2, 2, 1, 0>(), NULL, x, &z);
-  problem.AddResidualBlock(new MockCostFunctionBase<1, 3, 0, 0>(), NULL, y);
+  problem.AddResidualBlock(new MockCostFunctionBase<2, 2>(), NULL, x);
+  problem.AddResidualBlock(new MockCostFunctionBase<3, 1, 2>(), NULL, &z, x);
+  problem.AddResidualBlock(new MockCostFunctionBase<4, 1, 3>(), NULL, &z, y);
+  problem.AddResidualBlock(new MockCostFunctionBase<5, 1, 3>(), NULL, &z, y);
+  problem.AddResidualBlock(new MockCostFunctionBase<1, 2, 1>(), NULL, x, &z);
+  problem.AddResidualBlock(new MockCostFunctionBase<2, 1, 3>(), NULL, &z, y);
+  problem.AddResidualBlock(new MockCostFunctionBase<2, 2, 1>(), NULL, x, &z);
+  problem.AddResidualBlock(new MockCostFunctionBase<1, 3>(), NULL, y);
 
   TripletSparseMatrix expected_block_sparse_jacobian(3, 8, 14);
   {
@@ -386,7 +388,7 @@
   double x[2];
   x[0] = 1.0;
   x[1] = std::numeric_limits<double>::quiet_NaN();
-  problem.AddResidualBlock(new MockCostFunctionBase<1, 2, 0, 0>(), NULL, x);
+  problem.AddResidualBlock(new MockCostFunctionBase<1, 2>(), NULL, x);
   string error;
   EXPECT_FALSE(problem.program().ParameterBlocksAreFinite(&error));
   EXPECT_NE(error.find("has at least one invalid value"),
@@ -396,7 +398,7 @@
 TEST(Program, InfeasibleParameterBlock) {
   ProblemImpl problem;
   double x[] = {0.0, 0.0};
-  problem.AddResidualBlock(new MockCostFunctionBase<1, 2, 0, 0>(), NULL, x);
+  problem.AddResidualBlock(new MockCostFunctionBase<1, 2>(), NULL, x);
   problem.SetParameterLowerBound(x, 0, 2.0);
   problem.SetParameterUpperBound(x, 0, 1.0);
   string error;
@@ -407,7 +409,7 @@
 TEST(Program, InfeasibleConstantParameterBlock) {
   ProblemImpl problem;
   double x[] = {0.0, 0.0};
-  problem.AddResidualBlock(new MockCostFunctionBase<1, 2, 0, 0>(), NULL, x);
+  problem.AddResidualBlock(new MockCostFunctionBase<1, 2>(), NULL, x);
   problem.SetParameterLowerBound(x, 0, 1.0);
   problem.SetParameterUpperBound(x, 0, 2.0);
   problem.SetParameterBlockConstant(x);
diff --git a/internal/ceres/reorder_program_test.cc b/internal/ceres/reorder_program_test.cc
index be548ef..cf3e9f6 100644
--- a/internal/ceres/reorder_program_test.cc
+++ b/internal/ceres/reorder_program_test.cc
@@ -45,9 +45,8 @@
 using std::vector;
 
 // Templated base class for the CostFunction signatures.
-template <int kNumResiduals, int N0, int N1, int N2>
-class MockCostFunctionBase : public
-SizedCostFunction<kNumResiduals, N0, N1, N2> {
+template <int kNumResiduals, int... Ns>
+class MockCostFunctionBase : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   virtual bool Evaluate(double const* const* parameters,
                         double* residuals,
@@ -57,8 +56,8 @@
   }
 };
 
-class UnaryCostFunction : public MockCostFunctionBase<2, 1, 0, 0> {};
-class BinaryCostFunction : public MockCostFunctionBase<2, 1, 1, 0> {};
+class UnaryCostFunction : public MockCostFunctionBase<2, 1> {};
+class BinaryCostFunction : public MockCostFunctionBase<2, 1, 1> {};
 class TernaryCostFunction : public MockCostFunctionBase<2, 1, 1, 1> {};
 
 TEST(_, ReorderResidualBlockNormalFunction) {
diff --git a/internal/ceres/solver_test.cc b/internal/ceres/solver_test.cc
index d11fef4..6acae0b 100644
--- a/internal/ceres/solver_test.cc
+++ b/internal/ceres/solver_test.cc
@@ -453,8 +453,8 @@
   EXPECT_TRUE(options.IsValid(&message));
 }
 
-template<int kNumResiduals, int N1 = 0, int N2 = 0, int N3 = 0>
-class DummyCostFunction : public SizedCostFunction<kNumResiduals, N1, N2, N3> {
+template <int kNumResiduals, int... Ns>
+class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
diff --git a/internal/ceres/trust_region_preprocessor_test.cc b/internal/ceres/trust_region_preprocessor_test.cc
index 0c91e21..47cc4fb 100644
--- a/internal/ceres/trust_region_preprocessor_test.cc
+++ b/internal/ceres/trust_region_preprocessor_test.cc
@@ -28,6 +28,7 @@
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
+#include <array>
 #include <map>
 
 #include "ceres/ordered_groups.h"
@@ -113,8 +114,8 @@
   EXPECT_TRUE(preprocessor.Preprocess(options, &problem, &pp));
 }
 
-template<int kNumResiduals, int N1 = 0, int N2 = 0, int N3 = 0>
-class DummyCostFunction : public SizedCostFunction<kNumResiduals, N1, N2, N3> {
+template <int kNumResiduals, int... Ns>
+class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
@@ -127,30 +128,13 @@
       return true;
     }
 
-    if (jacobians[0] != NULL) {
-      MatrixRef j(jacobians[0], kNumResiduals, N1);
-      j.setOnes();
-      j *= kNumResiduals * N1;
-    }
-
-    if (N2 == 0) {
-      return true;
-    }
-
-    if (jacobians[1] != NULL) {
-      MatrixRef j(jacobians[1], kNumResiduals, N2);
-      j.setOnes();
-      j *= kNumResiduals * N2;
-    }
-
-    if (N3 == 0) {
-      return true;
-    }
-
-    if (jacobians[2] != NULL) {
-      MatrixRef j(jacobians[2], kNumResiduals, N3);
-      j.setOnes();
-      j *= kNumResiduals * N3;
+    std::array<int, sizeof...(Ns)> N{Ns...};
+    for (size_t i = 0; i < N.size(); ++i) {
+      if (jacobians[i] != NULL) {
+        MatrixRef j(jacobians[i], kNumResiduals, N[i]);
+        j.setOnes();
+        j *= kNumResiduals * N[i];
+      }
     }
 
     return true;