更多 C++ 慣用法/Traits
外觀
能夠使用通用介面來獲取關於型別的詳細資訊,即使該型別無法更改為符合任何通用介面。
函式模板可能需要根據關於這些型別的詳細資訊對不同型別進行不同的行為。如果只有使用者定義的型別可以具有編碼關於封閉型別的成員和成員型別的成員,那麼內建型別(如整數和指標)將需要很多特殊情況。透過使用一個單獨的 Traits 類,其中包含對可以修改以包含某些成員的型別的基本特化,以及對不能修改的型別的特化,函式仍然可以透過使用 Traits 類來使用通用介面。
所有 Traits 類的大小為零,並且只包含靜態成員或子型別。基本特化通常從其 Traits 被獲取的類的成員中獲取值或型別。(在下面的示例中,成員型別來自基類。)特化透過其他方式獲取值或型別,以保持介面的一致性。Traits 的好處在於它們是非侵入式的。這允許它們應用於內建型別,就像下面針對陣列的 container_traits 特化一樣。這也允許追溯建模。
namespace detail{
template <class C>
concept container = requires {
typename C::value_type;
typename C::size_type;
typename C::difference_type;
typename C::reference;
typename C::const_reference;
typename C::iterator;
typename C::const_iterator;
};
template <class C>
struct container_mixin{};
template <container C>
struct container_mixin<C>{
using value_type = typename C::value_type;
using size_type = typename C::size_type;
using difference_type = typename C::difference_type;
using reference = typename C::reference;
using const_reference = typename C::const_reference;
using iterator = typename C::iterator;
using const_iterator = typename C::const_iterator;
};
template <class C>
struct allocator_mixin{};
template <container C>
requires requires {typename C::allocator_type;}
struct allocator_mixin<C>{
using allocator_type = typename C::allocator_type;
};
template <class C>
struct reverse_iterator_mixin{};
template <container C>
requires requires {
typename C::reverse_iterator;
typename C::const_reverse_iterator;
}
struct reverse_iterator_mixin<C>{
using reverse_iterator = typename C::reverse_iterator;
using const_reverse_iterator = typename C::const_reverse_iterator;
};
template <class C>
struct pointer_mixin{};
template <container C>
requires requires {
typename C::pointer;
typename C::const_pointer;
}
struct pointer_mixin<C>{
using pointer = typename C::pointer;
using const_pointer = typename C::const_pointer;
};
}
// Primary template
template <class C>
struct container_traits :
public detail::container_mixin<C>,
public detail::allocator_mixin<C>,
public detail::reverse_iterator_mixin<C>,
public detail::pointer_mixin<C>
{};
// Specialization for arrays, cannot add typedef members to arrays
template <class T, std::size_t N>
struct container_traits<T[N]>{
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = T&;
using const_reference = const T&;
using pointer = T*;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
};
std::allocator_traitsstd::iterator_traitsstd::pointer_traitsstd::numeric_limitsstd::common_typestd::basic_common_reference