如果我有模板:
template <class T>
struct Item
{
T _value;
};
我可以这样做:
// ...
Item<int> x = { 42 }; // declared as an int
// ...
decltype(x._value) y = 20; // 'y' is also an int
但是可以将decltype
存储到变量中以便以后使用吗?
为什么?
我想将项的值存储为指针。
像std::vector<Item*>
这样的东西但是因为它们是模板我必须将它们存储为void
的指针:
std::vector<void*> is;
is.push_back(new Item<int>());
is.push_back(new Item<double>());
is.push_back(new Item<float>());
这一切都很好,但是当需要删除指针时,我需要将void*
重新转换回正确的类型(因此调用析构函数):
delete (Item<int>*)is[0];
如果我知道这种类型,我可以这样做:
delete (Item<decltype(whatever)>*)is[0];
因此我需要存储decltype
。
我希望这是有道理的。
答案 0 :(得分:6)
decltype
是一种语言功能,允许您在编译时检索类型。您似乎希望“存储”该类型,以便您可以在运行时正确delete
在动态存储上分配的对象。假设是这种情况,decltype
在这里没有帮助。
您有多种选择:
在评论中使用某种形式的类型删除工具,例如Boost.Variant
或Boost.Any
,如 Baum mit Augen 所示。
使您的对象成为多态层次结构的一部分并使用智能指针:
struct ItemBase
{
virtual ~ItemBase() { }
};
template <class T>
struct Item : ItemBase
{
T _value;
};
int main()
{
std::vector<std::unique_ptr<ItemBase>> items;
items.emplace_back(std::make_unique<Item<int>>());
items.emplace_back(std::make_unique<Item<float>>());
items.emplace_back(std::make_unique<Item<double>>());
}
答案 1 :(得分:5)
如果问题只是删除它们,您可以将unique_ptr
与自定义删除器一起使用,而不是使用裸指针。
您无需修改层次结构即可执行此操作
举个例子:
std::vector<std::unique_ptr<void, void(*)(void*)>> is;
is.push_back(std::unique_ptr<void, void(*)(void*)>{new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); }});
使用emplace_back
代替push_back
时更好:
std::vector<std::unique_ptr<void, void(*)(void*)>> is;
is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); });
它遵循基于OP代码的最小的工作示例:
#include<vector>
#include<memory>
template<typename>
struct Item {};
int main() {
using Deleter = void(*)(void*);
std::vector<std::unique_ptr<void, Deleter>> is;
is.emplace_back(new Item<int>(), [](void *ptr) { delete static_cast<Item<int>*>(ptr); });
is.emplace_back(new Item<double>(), [](void *ptr) { delete static_cast<Item<double>*>(ptr); });
is.emplace_back(new Item<float>(), [](void *ptr) { delete static_cast<Item<float>*>(ptr); });
}
答案 2 :(得分:1)
您可以存储删除
所以使用std::shared_ptr
,它变为:
std::vector<std::shared_ptr<void>> items;
// The simplest
items.push_back(std::make_shared<Item<int>>(/*args...*/));
// Explicitly specify the (default) deleter
items.push_back(std::shared_ptr<void>{new Item<double>(/*args...*/),
std::default_delete<Item<double>>{}});
// Explicitly specify the (default) allocator
items.push_back(
std::allocate_shared<Item<float>>(std::allocator<Item<float>>{} /*, args...*/);