]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // | |
3 | // (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost | |
4 | // Software License, Version 1.0. (See accompanying file | |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // See http://www.boost.org/libs/container for documentation. | |
8 | // | |
9 | ////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef BOOST_CONTAINER_USES_ALLOCATOR_HPP | |
12 | #define BOOST_CONTAINER_USES_ALLOCATOR_HPP | |
13 | ||
14 | #include <boost/container/uses_allocator_fwd.hpp> | |
15 | #include <boost/container/detail/type_traits.hpp> | |
16 | ||
17 | namespace boost { | |
18 | namespace container { | |
19 | ||
20 | //! <b>Remark</b>: if a specialization constructible_with_allocator_suffix<X>::value is true, indicates that T may be constructed | |
21 | //! with an allocator as its last constructor argument. Ideally, all constructors of T (including the | |
22 | //! copy and move constructors) should have a variant that accepts a final argument of | |
23 | //! allocator_type. | |
24 | //! | |
25 | //! <b>Requires</b>: if a specialization constructible_with_allocator_suffix<X>::value is true, T must have a nested type, | |
26 | //! allocator_type and at least one constructor for which allocator_type is the last | |
27 | //! parameter. If not all constructors of T can be called with a final allocator_type argument, | |
28 | //! and if T is used in a context where a container must call such a constructor, then the program is | |
29 | //! ill-formed. | |
30 | //! | |
31 | //! <code> | |
32 | //! template <class T, class Allocator = allocator<T> > | |
33 | //! class Z { | |
34 | //! public: | |
35 | //! typedef Allocator allocator_type; | |
36 | //! | |
37 | //! // Default constructor with optional allocator suffix | |
38 | //! Z(const allocator_type& a = allocator_type()); | |
39 | //! | |
40 | //! // Copy constructor and allocator-extended copy constructor | |
41 | //! Z(const Z& zz); | |
42 | //! Z(const Z& zz, const allocator_type& a); | |
43 | //! }; | |
44 | //! | |
45 | //! // Specialize trait for class template Z | |
46 | //! template <class T, class Allocator = allocator<T> > | |
47 | //! struct constructible_with_allocator_suffix<Z<T,Allocator> > | |
48 | //! { static const bool value = true; }; | |
49 | //! </code> | |
50 | //! | |
51 | //! <b>Note</b>: This trait is a workaround inspired by "N2554: The Scoped A Model (Rev 2)" | |
52 | //! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as | |
53 | //! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. | |
54 | //! Applications aiming portability with several compilers should always define this trait. | |
55 | //! | |
56 | //! In conforming C++11 compilers or compilers supporting SFINAE expressions | |
57 | //! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used | |
58 | //! to detect if a type should be constructed with suffix or prefix allocator arguments. | |
59 | template <class T> | |
60 | struct constructible_with_allocator_suffix | |
61 | { static const bool value = false; }; | |
62 | ||
63 | //! <b>Remark</b>: if a specialization constructible_with_allocator_prefix<X>::value is true, indicates that T may be constructed | |
64 | //! with allocator_arg and T::allocator_type as its first two constructor arguments. | |
65 | //! Ideally, all constructors of T (including the copy and move constructors) should have a variant | |
66 | //! that accepts these two initial arguments. | |
67 | //! | |
68 | //! <b>Requires</b>: specialization constructible_with_allocator_prefix<X>::value is true, T must have a nested type, | |
69 | //! allocator_type and at least one constructor for which allocator_arg_t is the first | |
70 | //! parameter and allocator_type is the second parameter. If not all constructors of T can be | |
71 | //! called with these initial arguments, and if T is used in a context where a container must call such | |
72 | //! a constructor, then the program is ill-formed. | |
73 | //! | |
74 | //! <code> | |
75 | //! template <class T, class Allocator = allocator<T> > | |
76 | //! class Y { | |
77 | //! public: | |
78 | //! typedef Allocator allocator_type; | |
79 | //! | |
80 | //! // Default constructor with and allocator-extended default constructor | |
81 | //! Y(); | |
82 | //! Y(allocator_arg_t, const allocator_type& a); | |
83 | //! | |
84 | //! // Copy constructor and allocator-extended copy constructor | |
85 | //! Y(const Y& yy); | |
86 | //! Y(allocator_arg_t, const allocator_type& a, const Y& yy); | |
87 | //! | |
88 | //! // Variadic constructor and allocator-extended variadic constructor | |
89 | //! template<class ...Args> Y(Args&& args...); | |
90 | //! template<class ...Args> | |
91 | //! Y(allocator_arg_t, const allocator_type& a, BOOST_FWD_REF(Args)... args); | |
92 | //! }; | |
93 | //! | |
94 | //! // Specialize trait for class template Y | |
95 | //! template <class T, class Allocator = allocator<T> > | |
96 | //! struct constructible_with_allocator_prefix<Y<T,Allocator> > | |
97 | //! { static const bool value = true; }; | |
98 | //! | |
99 | //! </code> | |
100 | //! | |
101 | //! <b>Note</b>: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" | |
102 | //! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as | |
103 | //! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. | |
104 | //! Applications aiming portability with several compilers should always define this trait. | |
105 | //! | |
106 | //! In conforming C++11 compilers or compilers supporting SFINAE expressions | |
107 | //! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used | |
108 | //! to detect if a type should be constructed with suffix or prefix allocator arguments. | |
109 | template <class T> | |
110 | struct constructible_with_allocator_prefix | |
111 | { static const bool value = false; }; | |
112 | ||
113 | #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
114 | ||
115 | namespace container_detail { | |
116 | ||
117 | template<typename T, typename Allocator> | |
118 | struct uses_allocator_imp | |
119 | { | |
120 | // Use SFINAE (Substitution Failure Is Not An Error) to detect the | |
121 | // presence of an 'allocator_type' nested type convertilble from Allocator. | |
122 | private: | |
123 | typedef char yes_type; | |
124 | struct no_type{ char dummy[2]; }; | |
125 | ||
126 | // Match this function if T::allocator_type exists and is | |
127 | // implicitly convertible from Allocator | |
128 | template <class U> | |
129 | static yes_type test(typename U::allocator_type); | |
130 | ||
131 | // Match this function if T::allocator_type exists and it's type is `erased_type`. | |
132 | template <class U, class V> | |
133 | static typename container_detail::enable_if | |
134 | < container_detail::is_same<typename U::allocator_type, erased_type> | |
135 | , yes_type | |
136 | >::type test(const V&); | |
137 | ||
138 | // Match this function if TypeT::allocator_type does not exist or is | |
139 | // not convertible from Allocator. | |
140 | template <typename U> | |
141 | static no_type test(...); | |
142 | static Allocator alloc; // Declared but not defined | |
143 | ||
144 | public: | |
145 | static const bool value = sizeof(test<T>(alloc)) == sizeof(yes_type); | |
146 | }; | |
147 | ||
148 | } //namespace container_detail { | |
149 | ||
150 | #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED | |
151 | ||
152 | //! <b>Remark</b>: Automatically detects whether T has a nested allocator_type that is convertible from | |
153 | //! Allocator. Meets the BinaryTypeTrait requirements ([meta.rqmts] 20.4.1). A program may | |
154 | //! specialize this type to define uses_allocator<X>::value as true for a T of user-defined type if T does not | |
155 | //! have a nested allocator_type but is nonetheless constructible using the specified Allocator where either: | |
156 | //! the first argument of a constructor has type allocator_arg_t and the second argument has type Alloc or | |
157 | //! the last argument of a constructor has type Alloc. | |
158 | //! | |
159 | //! <b>Result</b>: uses_allocator<T, Allocator>::value== true if a type T::allocator_type | |
160 | //! exists and either is_convertible<Alloc, T::allocator_type>::value != false or T::allocator_type | |
161 | //! is an alias `erased_type`. False otherwise. | |
162 | template <typename T, typename Allocator> | |
163 | struct uses_allocator | |
164 | : container_detail::uses_allocator_imp<T, Allocator> | |
165 | {}; | |
166 | ||
167 | }} //namespace boost::container | |
168 | ||
169 | #endif //BOOST_CONTAINER_USES_ALLOCATOR_HPP |