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
};