![](/img/trans.png)
[英]Different behaviour of my type_trait in templated/non-templated code
[英]Why specializing a type_trait could result in undefined behaviour?
根據標准§20.10.2/ 1標題<type_traits>
概要[meta.type.synop]:
1
除非另有說明,否則為本子條款中定義的任何類模板添加特殊化的程序的行為是未定義的。
這個特定的條款與STL應該是可擴展的一般概念相矛盾,並且阻止我們擴展類型特征,如下例所示:
namespace std {
template< class T >
struct is_floating_point<std::complex<T>> : std::integral_constant
<
bool,
std::is_same<float, typename std::remove_cv<T>::type>::value ||
std::is_same<double, typename std::remove_cv<T>::type>::value ||
std::is_same<long double, typename std::remove_cv<T>::type>::value
> {};
}
其中std::is_floating_point
被擴展為處理具有底層浮點類型的complex
。
對於is_floating_point
為1的主要類型類別,有一個設計不變量:
對於任何給定類型
T
,其中一個主要類型類別的值成員的計算結果為true
。
參考:(20.10.4.1主要類型類別[meta.unary.cat])
檢查一些未知的泛型類型時,程序員可以依靠這個不變的通用代碼T
:也就是說,如果is_class<T>::value
是true
,那么我們就需要檢查is_floating_point<T>::value
。 我們保證后者是false
。
下圖是表示主要和復合類型特征的圖表(此圖頂部的葉子是主要類別)。
http://howardhinnant.github.io/TypeHiearchy.pdf
如果允許(例如) std::complex<double>
對is_class
和is_floating_point
都回答為true,那么這個有用的不變量就會被破壞。 程序員將不再能夠依賴於如果is_floating_point<T>::value == true
,則T
必須是float
, double
或long double
。
現在有一些特征,標准“另有說法”,並且允許對用戶定義類型進行專門化。 common_type<T, U>
就是這樣的特質。
對於主要和復合類型的特征,沒有計划放寬對這些特征進行專門化的限制。 這樣做會損害這些特征對C ++中可生成的每種類型進行精確和唯一分類的能力。
添加霍華德的答案(附例)。
如果允許用戶專門化類型特征,他們可能會(故意或錯誤地)撒謊,標准庫不再能確保其行為是正確的。
例如,當復制std::vector<T>
類型的對象時,流行實現所執行的優化是調用std::memcpy
來復制所有元素, 前提是T
可以簡單地復制構造 。 他們可能會使用std::is_trivially_copy_constructible<T>
來檢測優化是否安全。 如果沒有,那么實現將回退到安全但速度較慢的方法,該方法循環遍歷元素並調用T
的復制構造函數。
現在,如果一個專門std::is_trivially_copy_constructible
為T = std::shared_ptr<my_type>
是這樣的:
namespace std {
template <>
class is_trivially_copy_constructible<std::shared_ptr<my_type>> : std::true_type {
};
}
然后復制std::vector<std::shared_ptr<my_type>>
將是災難性的。
這不是標准庫實現的錯,而是專業化作者的錯。 在某種程度上,這就是OP提供的報價所說:“這是你的錯,不是我的錯。”
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.