可变模板和new
Variadic templates and new
我有这样一个类模板:
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)...);
}
};
对于一个模板参数可以正常工作,但是对于多个参数我得到这个错误:
error: too many arguments to function call, expected 1, have 2
我如何使用可变模板与new
这种方式?正确的语法是什么?
编辑:我想我的问题不是很清楚。我想要的是:
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);
我的编译器是clang 163.7.1,带有这个标志:-std=c++0x
.
vector::push_back
期望一个参数,所以你不能在函数调用中扩展可变模板。我还为基类(所有其他类都是从它派生的)添加了一个模板参数。
这是编译的东西。
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;
}
您可以完成此操作,但由于您直接编写表达式,因此有点迂回。您需要为可变模板参数列表中的每个参数调用一次push_back
。
你如何做到这一点?通过对每个模板参数调用一次递归函数:
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);
}
这里我们有两个fill
函数的重载,一个有可变的模板参数列表,一个没有——这是递归的基本情况。只要还有至少两个模板参数,就调用第一个版本。如果只剩下一个参数,则调用第二个参数。
在构造函数中这样调用:
fill<TestCase, T...>(test_cases);
包扩展只能在选定的几种情况下发生,不能用于任意表达式或语句。但是,由于其中一种情况是列表初始化,并且由于操作顺序是为列表初始化语法的大括号初始化式定义的,因此始终可以展开任意语句。即:
typedef std::initializer_list<int> expand;
expand { ( test_cases.push_back(new T), void(), 0 )... };
void()
的技巧是抑制对重载operator,
的任何调用。这里完全不相关,但我已经包含了它,因为它可能在宏中重构功能时很有用:
#define EXPAND( exp )
std::initializer_list<int> { ( (exp), void(), 0 )... }
// No use of '...', it's in the macro body
EXPAND(( test_cases.push_back(new T) ));
与此相关的是,在这种特殊情况下,您可以通过如下方式编写构造函数来使用vector的initializer_list
支持
Test()
:test_cases{ new T ... }
{ }
或者由于某种原因不能使用构造函数初始化式
时使用赋值Test() {
test_cases = { new T ... };
}
也许你想要一个元组在你的std::vector?不确定这是否是你想要的,但这至少可以在我的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;
}
我突然想到你想要一个任何类型的动态向量(虽然我自己没有亲自去看,但我的一个朋友告诉我在boost库中显然有类似的东西),而不是模板向量。
模板vector基本上是可以采用一种定义类型中的任何一种的vector(要么全是整型,要么全是双精度,要么全是浮点数,但不是整型、双精度和浮点数)。
通常没有这样的类的原因是每个项在内存中占用不同的块大小(char是一个字节,int可能是4个字节等),并且在查找时需要额外的资源才能知道会发生什么(正常的存储是连续的……如果vector '基本上'是一个数组,那么它是什么呢?
如果你想构建自己的(我尝试过),你会看到void *指针,动态内存分配和一大堆涉及类型转换的头痛问题(我不知道有任何自动方法可以在幕后正确地对项目进行类型转换,但其他人可能能够参与)。
- 没有找到相关文章