我最近一直在嘗試在 C 中擴展一個非值引數包。這可能嗎?如果不是,為什么?
我的意思是,正如您所看到的,在注釋行中//,給定TypeMap類的引數包,我該如何呼叫addType<T>()每種型別的引數包?提前致謝!
template <typename... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[typeid(Type).name()] = std::make_unique<Type>(0).get();
}
public:
std::map<const char*, vari_cmps> typemap{};
TypeMap()
{
(addType<T,...>()); // Idk how to use this in order to make it work
}
~TypeMap()
{
typemap.clear();
}
};
uj5u.com熱心網友回復:
正如@HolyBlackCat 已經在評論中回答的那樣,您可以像這樣擴展它:
TypeMap() {
(addType<T>(), ...);
}
如果 T 是std::string, int, float這將擴展為:
TypeMap() {
(addType<std::string>(), addType<int>(), addType<float>());
}
但是,此代碼片段中還有一些問題:
1.addType()
addType() 由于 unique_ptr 在您將物件放入地圖后會洗掉它,因此不會像您預期的那樣作業。
.get()僅檢索由unique_ptr管理但不轉移所有權的指標,因此 unique_ptr 一旦超出范圍仍將洗掉指向的物件,在您的映射中留下一個懸空指標。
所以你addType()的大致相當于:
template<typename Type>
void addType() {
Type* tptr = new Type(0); // unique pointer constructs object
typemap[typeid(Type).name()] = tptr; // insert pointer value of unique pointer
delete tptr; // unique pointer destructs
}
您可以通過在將其值插入映射后釋放 unique_ptr 然后在解構式中清理它來解決此問題:
template<typename Type>
void addType() {
auto ptr = std::make_unique<Type>(0);
typemap[typeid(Type).name()] = ptr.get();
ptr.release(); // now unique_ptr won't delete the object
}
~TypeMap() {
// cleanup all pointers
for(auto& [name, ptrVariant] : typemap)
std::visit([](auto ptr) { delete ptr; }, ptrVariant);
}
2.考慮使用std::type_index而不是const char*作為映射鍵
std::type_info::name() 回傳給定型別的實作定義名稱,因此您無法保證您將獲得給定型別的唯一名稱。
回傳包含型別名稱的實作定義的以空字符結尾的字串。不提供任何保證;特別是,對于多種型別,回傳的字串可以是相同的,并且在同一程式的呼叫之間會發生變化。
std::type_index另一方面,專門為此目的構建 - 使用型別作為鍵 - 并帶有所有比較運算子和專業化std::hash,因此您可以開箱即用地使用它。std::mapstd::unordered_map
例如:
template <class... T>
class TypeMap
{
using vari_cmps = std::variant<T*...>;
private:
template<typename Type>
void addType()
{
typemap[std::type_index(typeid(Type))] = /* something */;
}
public:
std::map<std::type_index, vari_cmps> typemap{};
TypeMap() { /* ... */ }
~TypeMap() { /* ... */ }
template<class U>
U* get() {
auto it = typemap.find(std::type_index(typeid(U)));
return std::get<U*>(it->second);
}
};
考慮使用 std::tuple
std::tuple基本上是為此任務構建的,存盤任意型別的串列:
例如:
template <class... T>
class TypeMap
{
private:
std::tuple<std::unique_ptr<T>...> values;
public:
TypeMap() : values(std::make_unique<T>(0)...) {
}
template<class U> requires (std::is_same_v<U, T> || ...)
U& get() { return *std::get<std::unique_ptr<U>>(values); }
template<class U> requires (std::is_same_v<U, T> || ...)
U const& get() const { return *std::get<std::unique_ptr<U>>(values); }
};
用法:
TypeMap<int, double, float> tm;
tm.get<int>() = 12;
如果您愿意,您也可以將T's 直接存盤在元組中,避免額外的分配。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/410976.html
標籤:
上一篇:模板函式多載歧義
下一篇:Jinja2模板:輸出格式
