更多 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_traits
std::iterator_traits
std::pointer_traits
std::numeric_limits
std::common_type
std::basic_common_reference