Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

More C++ Idioms/Traits

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

Traits Intent To be able to use a common interface to get information about a type, even when the type cannot be changed to conform to any common interface. Also Known As Motivation A function template might need to behave differently for different types based on information about those types. If only user-defined types can have members and member types that encode information about the enclosing type, then there will need to be a lot of special cases for builtin types like integers and pointers. By using a separate traits class with a primary specialization for types that can be modified to include certain members and specializations for types that cannot, functions can still use a common interface by using the traits class. Solution and Sample Code All traits classes have zero size and only include static members or subtypes. The primary specialization usually gets the values or types from members of the class whose traits are gotten. (In the below example, the member types come from base classes.) The specializations get the values or types from other means in such a way that the interface remains consistent. The cool thing about traits is that they are non-intrusive. This allows them to be applied to built-in types, like the specialization of container_traits for arrays below. This also allows retroactive modeling. 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>; }; Known Uses std::allocator_traits std::iterator_traits std::pointer_traits std::numeric_limits std::common_type std::basic_common_reference Related Idioms Type Generator References Traits Introduction to Traits GENERIC<PROGRAMMING> Traits: The else-if-then of Types