EliSquared
EliSquared

Reputation: 1559

Create a Recursive Function for a Tuple in a Template

I am trying to create a Recursive Function in a factory pattern that iterates through a std::tuple with a variable number of elements. I have created my ConsoleShapeFactory like this:

template<size_t N, typename...Shapes>
class ConsoleShapeFactory : public ShapeFactory {
private:
  //Functions for shape creation
  void MakePoint(std::shared_ptr<CAD::Point>);

  //Recursive Router for shapes
  void MakeShapeRouter(std::tuple<Shapes...>&);

public:

  //Create Object Function
  std::tuple<Shapes...> CreateShapeTuple();


};

The CreateShapeTuple method is defined like this:

template<size_t N, typename...Shapes>
std::tuple<Shapes...> ConsoleShapeFactory<N, Shapes...>::CreateShapeTuple() {

  //Define return tuple and get size
  std::tuple<Shapes...> returnTuple;

  MakeShapeRouter(returnTuple);

  return returnTuple;

}

And the recursive MakeShapeRouter function looks like this (this does not work):

template<size_t N, typename...Shapes>
void ConsoleShapeFactory<N, Shapes...>::MakeShapeRouter(std::tuple<Shapes...>& tupShapes) {
  MakePoint(std::tuple::get<N-1>(tupShapes));

  ConsoleShapeFactory<N-1, Shapes...>::MakeShapeRouter(tupShapes); //This doesn't work
} 

And my attempt at a base case looks like this:

template<size_t N, typename...Shapes>
void ConsoleShapeFactory<1, Shapes...>::MakeShapeRouter(std::tuple<Shapes...>& tupShapes) {

  MakePoint(std::tuple::get<0>(tupShapes));
}

I am not sure how to set up my MakeShapeRouter function so that it can be called recursively and exit with a base case. Is what I am trying to do even possible?

*edit

Here is how I want to call the function in my main method if that helps:

int main()
{
  auto factory = ConsoleShapeFactory<2, std::shared_ptr<CAD::Point>, std::shared_ptr<CAD::Point>>();

  std::tuple<std::shared_ptr<CAD::Point>, std::shared_ptr<CAD::Point>> shapeTuple = factory.CreateShapeTuple();

  return 0;
}

*Edit 2

MakePoint implementation:

template<typename...Shapes>
void ConsoleShapeFactory<Shapes...>::MakePoint(std::shared_ptr<CAD::Point>& sp_point) {

  double x, y;

  x = 3;
  y = 4;

  sp_point = std::make_shared<CAD::Point>(x,y);
};

Upvotes: 1

Views: 586

Answers (1)

Jarod42
Jarod42

Reputation: 217283

Your method are not static, so you need an instance to call them.

ConsoleShapeFactory<N-1, Shapes...>::MakeShapeRouter(tupShapes); //This doesn't work

should be

ConsoleShapeFactory<N-1, Shapes...>{}.MakeShapeRouter(tupShapes);

But thing can be done without recursion thanks to std::index_sequence, something like:

template<typename... Shapes>
class ConsoleShapeFactory : public ShapeFactory {
private:
  //Functions for shape creation
  void MakePoint(std::shared_ptr<CAD::Point>);

  template <std::size_t ... Is>
  std::tuple<Shapes...> CreateShapeTuple(std::index_sequence<Is...>)
  {
      std::tuple<Shapes...> res;

      (MakePoint(std::get<Is>(res)), ...); // C++17

      /* or C++11
      const int dummy[] = {0, (MakePoint(std::get<Is>(res)), 0)...};
      static_cast<void>(dummy); // Avoid warning for unused variable.
      */

      return res;
  }

public:
  //Create Object Function
  std::tuple<Shapes...> CreateShapeTuple() {
       return CreateShapeTuple(std::index_sequence_for<Shapes...>());
  }
};

Upvotes: 1

Related Questions