[英]Templated member variables in C++
通常在編寫模板代碼時,我發現自己需要將模板類型的實例存儲在成員變量中。 例如,我可能需要緩存一個值以供以后使用。 我希望能夠將我的代碼編寫為:
struct Foo
{
template<typename T>
T member;
template<typename T>
void setMember(T value)
{
member<T> = value;
}
template<typename T>
T getMember()
{
return member<T>;
}
};
成員在使用時是專門的。 我的問題:
很明顯,我不想列出所有可能的類型(例如在std::variant
中),因為這不是生成式編程,並且如果庫的用戶與作者不同,則不可能。
編輯:我認為這在某種程度上回答了我上面的第三個問題。 原因是今天的編譯器無法將對象的實例化推遲到整個程序被解析之后: https://stackoverflow.com/a/27709454/3847255
這可以通過結合現有設施在圖書館中實現。
最簡單的實現是
std::unordered_map<std::type_index, std::any>
這有點低效,因為它將每個std::type_index
object 存儲兩次(一次在鍵中,一次在每個std::any
中),因此具有自定義透明 hash 和比較器的std::unordered_set<std::any>
會更多高效的; 不過,這將是更多的工作。
例子。
如您所說,圖書館的用戶可能與作者不同; 特別是, Foo
的析構函數不知道設置了哪些類型,但它必須找到這些對象並調用它們的析構函數,注意使用的類型集在Foo
的實例之間可能不同,因此這些信息必須存儲在運行時Foo
中的容器。
如果您對std::type_index
和std::any
隱含的 RTTI 開銷持謹慎態度,我們可以將它們替換為較低級別的等效項。 對於std::type_index
您可以使用指向static
標記變量模板實例化(或任何類似工具)的指針,對於std::any
您可以使用類型擦除的std::unique_ptr<void, void(*)(void*)>
其中刪除器是 function 指針:
using ErasedPtr = std::unique_ptr<void, void(*)(void*)>;
std::unordered_map<void*, ErasedPtr> member;
struct tag {};
template<class T> inline static tag type_tag;
member.insert_or_assign(&type_tag<T>, ErasedPtr{new T(value), [](void* p) {
delete static_cast<T*>(p);
}});
例子。 請注意,一旦您將std::unique_ptr
的刪除器設置為 function 指針,它就不再是默認可構造的,因此我們不能再使用operator[]
而必須使用insert_or_assign
和find
。 (同樣,我們遇到了相同的 DRY 違規/低效率,因為刪除器可以用作 map 的密鑰;利用這一點留給讀者練習。)
當前的 C++ 生成編碼設施是否可以使用這種模板化成員變量?
不,不完全是你描述的。 可以使封閉的 class 成為模板,並使用模板參數來描述類成員的類型。
template< typename T >
struct Foo
{
T member;
void setMember(T value)
{
member = value;
}
T getMember()
{
return member;
}
};
在 C++14 及更高版本中,有變量 templates ,但您不能使 class 的模板非靜態數據成員。
如果沒有,是否有任何關於這種語言功能的建議?
從來沒聽說過。
如果沒有,是否有任何技術原因導致這樣的事情是不可能的?
主要原因是這將導致無法定義 class 的二進制表示。 與模板相反,class 是一種類型,這意味着它的表示必須是固定的,這意味着在程序中的任何地方Foo
和Foo::member
必須表示相同的東西——相同的類型、相同的 object 大小和二進制布局,以及很快。 另一方面,模板不是類型(或者,在變量模板的情況下,不是對象)。 它在實例化時變為一個,並且每個模板實例化都是一個單獨的類型(在變量模板的情況下 - 對象)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.