我有一个简单的联合,其构造函数将其参数存储在相关成员中:
union Data
{
Data(int i) : _i(i) { }
Data(double d) : _d(d) { }
Data(char c) : _c(c) { }
int _i;
double _d;
char _c;
};
然后我有一个可变参数构造函数,它接受这些类型的参数并使用模板递归将它们存储在union的向量中:
template<typename... Ts>
DataStore(Ts... ts)
{
_data.reserve(sizeof...(ts));
store(ts...);
}
template<typename T, typename... Ts>
void store(T t, Ts... ts)
{
_data.push_back(t);
store(ts...);
}
void store()
{
// terminal condition
}
这将导致一系列匹配参数数量的vector::push_back
次调用。
这是填充联合向量的最有效/最快的方法吗?
是否有任何技巧(可以特定于x86-64 / Linux)我可以用来加快速度?
工作示例:
#include <iostream>
#include <vector>
union Data
{
Data(int i) : _i(i) { }
Data(double d) : _d(d) { }
Data(char c) : _c(c) { }
int _i;
double _d;
char _c;
};
struct DataStore
{
template<typename... Ts>
DataStore(Ts... ts)
{
_data.reserve(sizeof...(ts));
store(ts...);
}
template<typename T, typename... Ts>
void store(T t, Ts... ts)
{
_data.push_back(t);
store(ts...);
}
void store()
{
// terminal condition
}
std::vector<Data> _data;
};
int main()
{
DataStore d(1, 2.3, 'c');
std::cout << d._data.size() << '\n'
<< d._data[0]._i << '\n'
<< d._data[1]._d << '\n'
<< d._data[2]._c << '\n';
return 0;
}
答案 0 :(得分:5)
您可以直接初始化_data
。
template<typename... Ts>
DataStore(Ts... ts) : _data{ts...}
{}
答案 1 :(得分:4)
由于您的评论表明您反对使用初始化列表的简单方法,您可以这样做:
template<typename... T>
DataStore(T&&... ts)
{
_data.reserve(sizeof...(ts));
char dummy[] = { (_data.emplace_back(ts), '0')... };
}
那仍然会创建一个数组,但它是一个char
的数组,它可能会被优化掉,而且没有递归,你也不需要进行任何实例化。 store
功能模板。
数组的每个元素的初始化程序将参数包中的一个对象插入向量(按从左到右的顺序)。在此处使用emplace_back
可以将任何类型传递给DataStore
构造函数,这样您就不会在插入对象之前创建Data
个对象。这意味着没有制作副本:
DataStore d{ 1, '2', 3.0 };
(堆栈上只是一个未使用的char[3]
数组。)
如果你决定使用initializer_list
,你应该立即创建它,而不是在DataStore构造函数中创建它:
DataStore(std::initializer_list<Data> list) : _data(list) { }
现在您可以将任意数量的Data
对象传递给DataStore
构造函数,因此临时数组是在该构造函数之外创建的,然后直接传递给vector
成员。使用它,DataStore d{ Data{1}, Data{'2'}, Data{3.0} }
将构造一个包含三个对象的数组,然后将每个对象复制到向量中。
使用此构造函数,您无法DataStore{1, '2', 3.0}
,因为编译器无法从不同类型的braced-init-list创建initializer_list<Data>
。
答案 2 :(得分:1)
如何:
template<typename... Ts>
DataStore(Ts... ts)
{
_data = {ts...};
}
这将使用emplace_back
,因此您可以直接传递存储在union中的基本类型。