Search code examples
c++templatesvariadic-templatesparameter-pack

Using variadic template arguments for arbitrary number of classes


I have a situation where I need a class FaceProp that maintains/holds other classes for actual face types. These could be any types of faces like boundary faces, solid faces, internal faces etc etc. I wanted to implement FaceProp using the variadic parameter pack feature in C++, but I am not sure how this can be achieved.

I am attempting the following main class

 template<typename... FaceTypes>
 class FaceProp 

 {
     FaceProp(){
         /// here construct all those template argument classes. 
      }

  private:

   // declare here the classes to the FaceTypes.
   // e.g. If this class was declared with two face types I would have :
   //   std::unique_ptr<FaceType1> type1;
   //   std::unique_ptr<FaceType2> type2;

 }

I am not sure how declaring those would work since by the time of implementing I don't know how many/ and which face types I need to deal with. This is known by compiling time. In other words, when I want to declare the class FaceProp I would know how many face types to use

e.g.

 std::unique_ptr<FaceProp<facetype1, facetype2>> allfaces;

How is this best achieved?


Solution

  • An example of how to do this using std::tuple as suggested in the comments. I showed it with and without std::unique_ptr.

    template <typename... FaceTypes>
    class FaceProp
    {
       FaceProp() {
          m_tuple = {FaceTypes()...};
          m_uniqueTuples = {std::make_unique<FaceTypes>()...};
       }
    
    private:
       std::tuple<FaceTypes...> m_tuple;
       std::tuple<std::unique_ptr<FaceTypes>...> m_uniqueTuples;
    };
    

    The ... in the code expands the associated expression to include each type in the parameter pack. So, FaceProp<int, double> expands to:

    class FaceProp
    {
       FaceProp() {
          m_tuple = {int(), double()};
          m_uniqueTuples = {std::make_unique<int>(), std::make_unique<double>()};
       }
    
    private:
       std::tuple<int, double> m_tuple;
       std::tuple<std::unique_ptr<int>, std::unique_ptr<double>> m_uniqueTuples;
    };