Variadic Templates and New

I have this template template:

template<class... T> class Test { std::vector<TestCase*> test_cases; public: Test() { // Here, for each T an instance should be added to test_cases. test_cases.push_back((new T)...); } }; 

This works fine for one template argument, but for multiple arguments I get this error:

 error: too many arguments to function call, expected 1, have 2 

How can I use variable templates with new this way? What is the correct syntax?


EDIT: I think my question was not entirely clear. I want this:

 Test<TestCase1, TestCase2, TestCase3>; // The constructor will then be: test_cases.push_back(new TestCase1); test_cases.push_back(new TestCase2); test_cases.push_back(new TestCase3); 

My clag compiler is 163.7.1 with this flag: -std=c++0x .

+7
source share
6 answers

vector::push_back expects a single parameter, so you cannot expand a variational pattern in a function call. I also added a template parameter for the base class (from which all other classes are derived).

Here is something that compiles .

 struct base{}; struct d0 : base{}; struct d1 : base{}; struct d2 : base{}; #include <vector> // termination condition for helper function template <class T> void add(std::vector<T*>&) { } // helper function template <class T, class Head, class... Tail> void add(std::vector<T*>& v) { v.push_back(new Head()); add<T, Tail...>(v); } template <class T, class ... U> class test { std::vector<T*> vec; public: test() { add<T, U...>(vec); } }; int main() { test<base, d0,d1,d2> t; } 
+3
source

A package extension can occur only in a selected number of situations and does not work for arbitrary expressions or operators. However, since one of these situations is list initialization, and since the order of operations is defined for list-initialization syntax binding initializers, you can always deploy an arbitrary statement. To wit:

 typedef std::initializer_list<int> expand; expand { ( test_cases.push_back(new T), void(), 0 )... }; 

The void() triple is designed to suppress any call to an overloaded operator, It’s completely irrelevant here, but I turned it on, as it can be useful when refactoring functionality in a macro:

 #define EXPAND( exp ) \ std::initializer_list<int> { ( (exp), void(), 0 )... } // No use of '...', it in the macro body EXPAND(( test_cases.push_back(new T) )); 
+2
source

You can do this, but it's a bit of a circular motion since you are writing the expression directly. You must call push_back once for each argument in the argument list of the variational pattern.

How do you achieve this? Well, calling the recursive function once for each template argument:

 template <typename Base, typename T1, typename T2, typename... T> void fill(std::vector<Base*>& vec) { vec.push_back(new T1); fill<Base, T2, T...>(vec); } template <typename Base, typename T1> void fill(std::vector<Base*>& vec) { vec.push_back(new T1); } 

Here we have two overloads of the fill function, one with a variational list of template arguments and one without it is the case of a recursion base. As long as there are at least two template arguments, the first version is called. If only one argument is left, the second argument is called instead.

In the constructor, call it like this:

 fill<TestCase, T...>(test_cases); 
+2
source

In the corresponding note in this particular case, you can use the vector initializer_list support by writing the constructor as follows

 Test() :test_cases{ new T ... } { } 

Or using an assignment if for some reason you cannot use constructor initializers

 Test() { test_cases = { new T ... }; } 
+1
source

Perhaps you need a tuple inside your std :: vector? Not sure if this is what you intended, but it compiles, at least on my g ++ 4.6.1: D

 #include <vector> #include <utility> #include <functional> #include <string> template<class... T> class Test { std::vector<std::tuple<T*...>> test_cases; public: Test() { // Here, for each T an instance should be added to test_cases. test_cases.push_back(std::tuple<T*...>((new T)...)); } }; int main() { Test<int, float> foo; Test<std::string, double> bar; } 
0
source

It seems to me that you want a dynamic vector of any type (although I personally did not watch it myself, a friend told me that there was clearly something similar in the boost library), unlike the vector template.

A template vector is a vector that can take any of one specific type (either all ints, all paired, or all floating, but not ints and doubles and floats).

The reason why there is no such class as traditionally is because each element occupies a different block size in memory (a char is a byte, int can be 4 bytes, etc.), and this will require additional resources to search to know what to expect (normal storage is contiguous ... which is a vector, given that it is a "basically" array).

If you want to create your own (I tried), you look at void * pointers, dynamic memory allocation, and a number of headaches associated with type casting (I don’t know about any automatic method to properly attribute an element backstage, but others may be able to insert).

0
source

All Articles