Home > OS >  how to handle variadic template functions as class constructor and class members
how to handle variadic template functions as class constructor and class members

Time:08-21

I hope you are doing great.

I have a class for which I wants its constructor to take an undefined number of arguments, then I though about variadic template.

I can instantiate objects using constructor with no parameters and also with just one parameters, but when I try to use a constructor with two parameters, I get a compile time error like:

error: no matching function for call to 'pinBase::init(GPIO_TypeDef* const&, const long unsigned int&)' 
pinBase(const Args& ...rest){init(<----MARKS ERROR HERE--->rest...);}

This is how I conceived my class:

//pinBase.hh
class pinBase
{
  private:

    GPIO_TypeDef *_instance;

    GPIO_PIN _pin = PIN[0];
    GPIO_MODE _mode = INPUT;
    
    //these are the functions to which each individual expansion should be called
    void _init();
    void _init(GPIO_TypeDef* GPIOx);
    void _init(GPIO_PIN pin);
    
    //one of these two functions gets called by the constructor either with void or param of certain type
    void init(){_init();}
    template <class T>
    void init(T t){_init(t);}

 public:

    //constructor accepts void or multiple params ( ... can be empty)
    template <class ...Args>
    pinBase(const Args& ...rest){init(rest...);}
    ~pinBase();
}

This is my implementation file:

//pinBase.cpp
#include "pinBase.hh"
pinBase::~pinBase()
{
}

void pinBase::_init()
{
    uint8_t temp = 124; // I have set breakpoint here
}
void pinBase::_init(GPIO_TypeDef* GPIOx)
{
    _resetValues = *GPIOx; // I have set breakpoint here
}

void pinBase::_init(GPIO_PIN pin)
{
    _pin = pin; // I have set breakpoint here
}

This is main file:

//main.cpp
#include "stdint.h"
#include "pinBase.hh"

pinBase pin; //works perfect
pinBase otropin(GPIOA);//works perfect
pinBase andererpin(PIN_0);//works perfect

/**When commented,the program runs well 
*and gets to each of the breakpoints 
*with no problems at all.
**when uncommented, causes compile time error. 
*/
pinBase anotherpin(GPIOA, PIN_0); 

int main(void)
{
    
    while (1)
    {
        /* code */
    }
    
    return 0;
}

CodePudding user response:

You clarified that you expect a single call to init() for each variadic parameter.

What you are looking for is a fold expression (requires a C 17 compiler, or later):

template <class ...Args>
    pinBase(const Args& ...rest){ (init(rest), ...);}

The syntax you're using results in a single call to init(), with all parameters forwarded in the single function call. The parameter pack gets expanded into a single, forwarded, parameter pack.

A fold expression, on the other hand, should produce your expected result (and you should not need an init() overload with no parameters).

CodePudding user response:

The problem is not with the constructor itself but with the method pinBase::init. In particular, pinBase::init has only 1 parameter so you cannot call it with 2 or more arguments. That is, when you wrote:

init(rest...)

In the above, you're calling pinBase::init by passing all the arguments that the parameter pack has. But since init currently only has one parameter of type T, it cannot be called with 2 or more arguments.


To solve this you can make init a variadic as well as shown below:

class pinBase
{
  private:

//------------vvvvvvvv------------->T is a template parameter pack
    template <class... T>
//-------------vvv----------------->t is a function parameter pack
    void init(T... t){}

 //other code here as before
};

Working demo

  • Related