我正在制作一個Box<T>處理一些資料的結構。細節并不重要。
然而,一個重要的注意事項是它Box<T>可以存盤一個指標,但它可能不會。所以Box<int>和Box<int *>都是有效的。顯然,如果我們擁有,如果它是指標型別Box.data,我們將需要資料。delete這是我想出的適用于 C 11 的解決方案:
template <typename T> struct BoxTraits;
template <typename T> struct Box {
using traits_t = BoxTraits<T>;
T data;
~Box() = default; // not required, I know
T get_data() { return traits_t::get_data(this); }
};
template <typename T> struct Box<T *> {
using traits_t = BoxTraits<T *>;
T *data;
~Box() { delete data; }
T *get_data() { return traits_t::get_data(this); }
};
template <typename T> struct BoxTraits {
static T get_data(Box<T> *const box) { return box->data; }
};
Box::get_data這里是為了說明這個設計模式的一個問題。對于我想添加的每一個方法Box,我需要在每個專業中添加一些樣板。請注意,我還需要一個Box<T *const>專業。
這似乎是一個非常垃圾的解決方案。在 C 14 中,我可以使用if constexprtraitis_ptr<T>并且只需要在需要專門化的方法中撰寫額外的代碼......在 C 11 中有什么方法可以做到這一點嗎?
該解決方案更短,更清潔并且適用于Box<U *const>!
template <typename T> struct is_ptr { static const bool value = false; };
template <typename U> struct is_ptr<U *> { static const bool value = true; };
template <typename U> struct is_ptr<U *const> {
static const bool value = true;
};
template <typename T> struct Box {
T data;
~Box() {
if constexpr (is_ptr<T>::value) {
delete data;
}
}
T get_data() { return data; }
};
uj5u.com熱心網友回復:
首先,C 11 已經有了std::is_pointer,無需自己動手。您可以看到它繼承自std::true_type或std::false_type而不是定義自己的value成員。原因是標簽調度,if constexpr在這種情況下可以有效地替換:
template <typename T> struct Box {
T data;
~Box() {
destroy(std::is_pointer<T>{});
}
private:
void destroy(std::true_type) {
delete data;
}
void destroy(std::false_type) {} // nothing to do
};
演示
我認為這是 C 11 中基于型別特征委托給不同實作的最慣用的方式。在很多情況下,標簽調度可以替代if constexpr(來自 C 17,而不是 C 14),而且我相信后者總是會替代前者,而且更清晰。如果您滾動自己的型別特征,也可以在 C 11 之前使用標記調度。
最后一點:你不需要使用標準的型別特征,你可以這樣做:
template <typename T> struct is_ptr { static const bool value = false; };
template <typename T> struct is_ptr<T*> { static const bool value = true; };
template <typename T> struct is_ptr<T* const> { static const bool value = true; };
template <typename T> struct is_ptr<T* volatile> { static const bool value = true; };
template <typename T> struct is_ptr<T* const volatile> { static const bool value = true; };
template<bool b>
struct bool_constant {};
template<typename T>
struct Box {
T data;
~Box() {
destroy(bool_constant<is_ptr<T>::value>{});
}
private:
void destroy(bool_constant<true>) {
delete data;
}
void destroy(bool_constant<false>) {} // nothing to do
};
演示
然而,這幾乎相當于重新創建標準型別特征,但可能更糟。盡可能使用標準庫。
uj5u.com熱心網友回復:
我認為您對輔助型別有正確的想法,但我會像下面的示例所示那樣做。
template <typename B, typename T>
struct BoxTraits {
static T& get_data(B *const box) { return box->data; }
// ^--- important
static T const& get_data(B const* const box) { return box->data; }
};
template <typename T>
struct BoxTraits<Box<T*>, T> {
static T& get_data(Box<T*>* const box) { return *box->data; }
static T const& get_data(Box<T*> const* const box) { return *box->data; }
};
兩個版本總是回傳T,因此無論您的 Box 的有效負載如何,您都可以使用相同的版本。您可以在 Box 中添加型別別名,這樣您就不必傳遞模板引數:
typedef Traits BoxTraits<Box, T>; // in Box class
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/520995.html
標籤:C c 11模板
上一篇:嵌套資料框后變數的平均值
