Reputation: 1561
#include <stdlib.h>
#include <stdint.h>
#include <vector>
struct MyClass1 {
virtual ~MyClass1() = default;
};
template <typename T>
struct MyClass2 : public MyClass1 {};
template <class...C> class MyClass3 { //will be singleton class
public:
MyClass3()
{
make_classes<C...>(_class_vec);
}
private:
static const size_t _num_classes = sizeof...(C);
static uint8_t *_buf[_num_classes];
std::vector<MyClass1*> _class_vec;
void make_classes(std::vector<MyClass1*> &vec) {}
template <class First, class... Rest> void make_classes(std::vector<MyClass1*> &vec) {
static size_t count;
First* tmp = new (_buf[count++]) First;
vec.push_back(tmp);
make_classes<Rest...>(vec);
}
};
int main() {
auto foo = MyClass3<MyClass2<int>, MyClass2<char>>();
return 0;
}
I'm trying to pass a set of variadic template arguments to the constructor of Class3, and use placement new to put them in the cells of an appropriately sized pool, the first dimension of which is calculated at compile time. Then construct a vector of pointers to them with the type of the base object (the derived objects that are being passed into the template of Class3 are templated with a single variable type.)
This compiles OK, but when I go to create an object of type Class3 in main I get the following error:
prog.cpp: In instantiation of 'void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = MyClass2<char>; Rest = {}; C = {MyClass2<int>, MyClass2<char>}]':
prog.cpp:32:29: required from 'void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = MyClass2<int>; Rest = {MyClass2<char>}; C = {MyClass2<int>, MyClass2<char>}]'
prog.cpp:17:29: required from 'MyClass3<C>::MyClass3() [with C = {MyClass2<int>, MyClass2<char>}]'
prog.cpp:38:57: required from here
prog.cpp:32:29: error: no matching function for call to 'MyClass3<MyClass2<int>, MyClass2<char> >::make_classes(std::vector<MyClass1*>&)'
make_classes<Rest...>(vec);
^
prog.cpp:27:55: note: candidate: template<class First, class ... Rest> void MyClass3<C>::make_classes(std::vector<MyClass1*>&) [with First = First; Rest = {Rest ...}; C = {MyClass2<int>, MyClass2<char>}]
template <class First, class... Rest> void make_classes(std::vector<MyClass1*> &vec) {
^
prog.cpp:27:55: note: template argument deduction/substitution failed:
prog.cpp:32:29: note: couldn't deduce template parameter 'First'
make_classes<Rest...>(vec);
What's the correct way to accomplish this using variadic templates? Please keep in mind that I'm working on an embedded platform, so my compiler is C++11 compatible, but much of the STL and Boost is not really available to me.
Upvotes: 1
Views: 166
Reputation: 50540
Recursion in your code lacks the base case, that is the one having an empty parameter pack.
Non template member function does not take part to the game, for you are always explicitly specializing the template member function with the line:
make_classes<Rest...>(0, vec);
A possible solution would be this:
Modify your constructor:
MyClass3()
{
make_classes<C...>(0, _class_vec);
}
Update both your make_classes
functions:
template<typename... T>
std::enable_if_t<sizeof...(T)==0>
make_classes(int, std::vector<MyClass1*> &vec) {}
template <class First, class... Rest> void make_classes(char, std::vector<MyClass1*> &vec) {
static size_t count;
First* tmp = new (_buf[count++]) First;
vec.push_back(tmp);
make_classes<Rest...>(0, vec);
}
NOTE: it won't compile in any case, unless you also define _buf
somewhere.
Upvotes: 2
Reputation: 118300
The compilation error is because the last recursive call to make_classes
is:
make_classes<>(vec);
And, of course, this does not match the template function.
void make_classes(std::vector<MyClass1*> &vec) {}
This is not a template function. There's a difference between:
make_classes(vec);
and
make_classes<>(vec);
You could try specializing the template function, but with the whole thing inside a template class, this gets ugly rather quickly.
The easiest solution is to replace make_classes
() with:
template <class First> void make_1class(std::vector<MyClass1*> &vec)
{
static size_t count;
First* tmp = new (_buf[count++]) First;
vec.push_back(tmp);
}
template <typename OneClassLeft>
void make_classes(std::vector<MyClass1*> &vec)
{
make_1class<OneClassLeft>(vec);
}
template <class First, class Second, class ...Rest>
void make_classes(std::vector<MyClass1*> &vec)
{
make_1class<First>(vec);
make_classes<Second, Rest...>(vec);
}
Upvotes: 2
Reputation: 19761
You have a recursive call with no base case. Eventually you're calling make_classes<>(vec);
because when you called it with one type, First
ate that and Rest...
was left empty.
You need something to handle that base case template<class First>
and you should be good.
Upvotes: 1