我有一个模板容器类,需要将附加信息与用户指定类型的每个实例相关联。
容器指定包含指定类型和附加信息的包装器结构......
template<typename T> class Container
{
...
struct Wrapper
{
T mType;
int mInfo;
};
}
在初始化时,使用动态分配的Wrapper实例(即Wrapper *)填充容器。用户可以pop()一个实例,容器将返回一个转换为T *。用户可以push()一个实例,容器将转换回Wrapper *。
如果数据类型可以默认构造,这可以正常工作。但是,情况并非总是这样,我想让用户提供一个在初始化期间调用的分配函数,它构造了它喜欢的数据类型。容器可以要求该功能的特定签名。
template<typename T> template<typename F> void Container<T>::init(F allocator);
我正在努力解决的是在函数分配数据类型时如何分配包装器。我已经考虑过使用placement new,其中容器为Wrapper分配了足够的空间,并将地址传递给函数以进行数据类型的新放置。
有更简洁的方法吗?
答案 0 :(得分:0)
您不需要为此分配功能。相反,你需要像标准容器中的emplace_push。
答案 1 :(得分:0)
我只是将用于构造T的参数添加为Container的模板参数,并使用它们来构造T.为了允许动态构造T对象,容器构造函数接受一个指向函数的指针作为参数。参数是创建等级的整数,T构造函数的默认参数,并返回T构造函数的参数元组(std::tuple<U...> (*getInitParam)(int rank, U... params)
):
template<typename T, typename ...U>
class Container {
struct Wrapper {
T mType;
int mInfo;
Wrapper(int mInfo, U... params): mType(params...), mInfo(mInfo) {}
};
std::stack<Wrapper *> stack;
int get_mInfo() {
static int info = 0;
return info++;
}
std::tuple<U...> (*getInitParam)(int rank, U... params);
public:
T* pop() {
// should control stack is not empty
Wrapper *w = stack.top();
stack.pop();
return &w->mType;
}
void push(T* type) {
char *p = reinterpret_cast<char *>(type);
p -= offsetof(Wrapper, mType);
Wrapper *w = reinterpret_cast<Wrapper *>(p);
// would need to control that *w is a valid Wrapper
stack.push(w);
}
void init(int n, U... params) {
std::tuple<U...> orig = std::make_tuple(params...);
for (int i=0; i<n; i++) {
if (getInitParam != nullptr) {
std::tie(params...) = orig;
std::tuple<U...> tparams = (*getInitParam)(i, params...);
std::tie(params...) = tparams;
}
Wrapper *w = new Wrapper(get_mInfo(), params...);
stack.push(w);
}
}
Container(std::tuple<U...> (*getInitParam)(int rank, U... params) = nullptr)
: getInitParam(getInitParam) {}
~Container() {
while(! stack.empty()) {
Wrapper *w = stack.top();
delete w;
stack.pop();
}
}
};
用法示例:
std::tuple<size_t, char> doInit(int i, size_t szmin, char c) {
return std::make_tuple(szmin + i, c);
}
int main() {
Container<std::string, size_t, char> cont(&doInit);
cont.init(10, 5, 'x');
std::string* str0 = cont.pop();
std::string* str = cont.pop();
std::cout << *str0 << std::endl;
std::cout << *str << std::endl;
*str0 = "bar";
cont.push(str0);
cont.push(str);
str0 = cont.pop();
str = cont.pop();
std::cout << *str << std::endl;
cont.push(str);
cont.push(str0);
return 0;
}
这正确输出:
xxxxxxxxxxxxxx
xxxxxxxxxxxxx
bar
仍然需要实现mInfo用法,但它应该是一个起点......