1 /* Copyright 2003-2013 Joaquin M Lopez Munoz. 2 * Distributed under the Boost Software License, Version 1.0. 3 * (See accompanying file LICENSE_1_0.txt or copy at 4 * http://www.boost.org/LICENSE_1_0.txt) 5 * 6 * See http://www.boost.org/libs/multi_index for library home page. 7 */ 8 9 #ifndef BOOST_MULTI_INDEX_DETAIL_VARTEMPL_SUPPORT_HPP 10 #define BOOST_MULTI_INDEX_DETAIL_VARTEMPL_SUPPORT_HPP 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 /* Utilities for emulation of variadic template functions. Variadic packs are 17 * replaced by lists of BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS parameters: 18 * 19 * - typename... Args --> BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK 20 * - Args&&... args --> BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK 21 * - std::forward<Args>(args)... --> BOOST_MULTI_INDEX_FORWARD_PARAM_PACK 22 * 23 * Forwarding emulated with Boost.Move. A template functions foo_imp 24 * defined in such way accepts *exactly* BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS 25 * arguments: variable number of arguments is emulated by providing a set of 26 * overloads foo forwarding to foo_impl with 27 * 28 * BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL 29 * BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG (initial extra arg) 30 * 31 * which fill the extra args with boost::multi_index::detail::noarg's. 32 * boost::multi_index::detail::vartempl_placement_new works the opposite 33 * way: it acceps a full a pointer x to Value and a 34 * BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK and forwards to 35 * new(x) Value(args) where args is the argument pack after discarding 36 * noarg's. 37 * 38 * Emulation decays to the real thing when the compiler supports variadic 39 * templates and move semantics natively. 40 */ 41 42 #include <boost/config.hpp> 43 44 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)||\ 45 defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) 46 47 #include <boost/move/core.hpp> 48 #include <boost/move/utility.hpp> 49 #include <boost/preprocessor/arithmetic/add.hpp> 50 #include <boost/preprocessor/arithmetic/sub.hpp> 51 #include <boost/preprocessor/cat.hpp> 52 #include <boost/preprocessor/control/if.hpp> 53 #include <boost/preprocessor/facilities/empty.hpp> 54 #include <boost/preprocessor/facilities/intercept.hpp> 55 #include <boost/preprocessor/logical/and.hpp> 56 #include <boost/preprocessor/punctuation/comma.hpp> 57 #include <boost/preprocessor/punctuation/comma_if.hpp> 58 #include <boost/preprocessor/repetition/enum.hpp> 59 #include <boost/preprocessor/repetition/enum_params.hpp> 60 #include <boost/preprocessor/repetition/repeat_from_to.hpp> 61 #include <boost/preprocessor/seq/elem.hpp> 62 63 #if !defined(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS) 64 #define BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS 5 65 #endif 66 67 #define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK \ 68 BOOST_PP_ENUM_PARAMS( \ 69 BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,typename T) 70 71 #define BOOST_MULTI_INDEX_VARTEMPL_ARG(z,n,_) \ 72 BOOST_FWD_REF(BOOST_PP_CAT(T,n)) BOOST_PP_CAT(t,n) 73 74 #define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK \ 75 BOOST_PP_ENUM( \ 76 BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \ 77 BOOST_MULTI_INDEX_VARTEMPL_ARG,~) 78 79 #define BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG(z,n,_) \ 80 boost::forward<BOOST_PP_CAT(T,n)>(BOOST_PP_CAT(t,n)) 81 82 #define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK \ 83 BOOST_PP_ENUM( \ 84 BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \ 85 BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~) 86 87 namespace boost{namespace multi_index{namespace detail{ 88 struct noarg{}; 89 }}} 90 91 /* call vartempl function without args */ 92 93 #define BOOST_MULTI_INDEX_NULL_PARAM_PACK \ 94 BOOST_PP_ENUM_PARAMS( \ 95 BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS, \ 96 boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT) 97 98 #define BOOST_MULTI_INDEX_TEMPLATE_N(n) \ 99 template<BOOST_PP_ENUM_PARAMS(n,typename T)> 100 101 #define BOOST_MULTI_INDEX_TEMPLATE_0(n) 102 103 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX(z,n,data) \ 104 BOOST_PP_IF(n, \ 105 BOOST_MULTI_INDEX_TEMPLATE_N, \ 106 BOOST_MULTI_INDEX_TEMPLATE_0)(n) \ 107 BOOST_PP_SEQ_ELEM(0,data) /* ret */ \ 108 BOOST_PP_SEQ_ELEM(1,data) /* name_from */ ( \ 109 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~)) \ 110 { \ 111 return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ ( \ 112 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~) \ 113 BOOST_PP_COMMA_IF( \ 114 BOOST_PP_AND( \ 115 n,BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n))) \ 116 BOOST_PP_ENUM_PARAMS( \ 117 BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \ 118 boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT) \ 119 ); \ 120 } 121 122 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL( \ 123 ret,name_from,name_to) \ 124 BOOST_PP_REPEAT_FROM_TO( \ 125 0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \ 126 BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_AUX, \ 127 (ret)(name_from)(name_to)) 128 129 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX( \ 130 z,n,data) \ 131 BOOST_PP_IF(n, \ 132 BOOST_MULTI_INDEX_TEMPLATE_N, \ 133 BOOST_MULTI_INDEX_TEMPLATE_0)(n) \ 134 BOOST_PP_SEQ_ELEM(0,data) /* ret */ \ 135 BOOST_PP_SEQ_ELEM(1,data) /* name_from */ ( \ 136 BOOST_PP_SEQ_ELEM(3,data) BOOST_PP_SEQ_ELEM(4,data) /* extra arg */\ 137 BOOST_PP_COMMA_IF(n) \ 138 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~)) \ 139 { \ 140 return BOOST_PP_SEQ_ELEM(2,data) /* name_to */ ( \ 141 BOOST_PP_SEQ_ELEM(4,data) /* extra_arg_name */ \ 142 BOOST_PP_COMMA_IF(n) \ 143 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~) \ 144 BOOST_PP_COMMA_IF( \ 145 BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n)) \ 146 BOOST_PP_ENUM_PARAMS( \ 147 BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \ 148 boost::multi_index::detail::noarg() BOOST_PP_INTERCEPT) \ 149 ); \ 150 } 151 152 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG( \ 153 ret,name_from,name_to,extra_arg_type,extra_arg_name) \ 154 BOOST_PP_REPEAT_FROM_TO( \ 155 0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \ 156 BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG_AUX, \ 157 (ret)(name_from)(name_to)(extra_arg_type)(extra_arg_name)) 158 159 namespace boost{ 160 161 namespace multi_index{ 162 163 namespace detail{ 164 165 #define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX(z,n,name) \ 166 template< \ 167 typename Value \ 168 BOOST_PP_COMMA_IF(n) \ 169 BOOST_PP_ENUM_PARAMS(n,typename T) \ 170 > \ 171 Value* name( \ 172 Value* x \ 173 BOOST_PP_COMMA_IF(n) \ 174 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_ARG,~) \ 175 BOOST_PP_COMMA_IF( \ 176 BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n)) \ 177 BOOST_PP_ENUM_PARAMS( \ 178 BOOST_PP_SUB(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,n), \ 179 BOOST_FWD_REF(noarg) BOOST_PP_INTERCEPT)) \ 180 { \ 181 return new(x) Value( \ 182 BOOST_PP_ENUM(n,BOOST_MULTI_INDEX_VARTEMPL_FORWARD_ARG,~)); \ 183 } 184 185 #define BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(name) \ 186 BOOST_PP_REPEAT_FROM_TO( \ 187 0,BOOST_PP_ADD(BOOST_MULTI_INDEX_LIMIT_VARTEMPL_ARGS,1), \ 188 BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX, \ 189 name) 190 191 BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW(vartempl_placement_new) 192 193 #undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW_AUX 194 #undef BOOST_MULTI_INDEX_VARTEMPL_TO_PLACEMENT_NEW 195 196 } /* namespace multi_index::detail */ 197 198 } /* namespace multi_index */ 199 200 } /* namespace boost */ 201 202 #else 203 204 /* native variadic templates support */ 205 206 #include <utility> 207 208 #define BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK typename... Args 209 #define BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK Args&&... args 210 #define BOOST_MULTI_INDEX_FORWARD_PARAM_PACK std::forward<Args>(args)... 211 #define BOOST_MULTI_INDEX_NULL_PARAM_PACK 212 213 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL( \ 214 ret,name_from,name_to) \ 215 template<typename... Args> ret name_from(Args&&... args) \ 216 { \ 217 return name_to(std::forward<Args>(args)...); \ 218 } 219 220 #define BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG( \ 221 ret,name_from,name_to,extra_arg_type,extra_arg_name) \ 222 template<typename... Args> ret name_from( \ 223 extra_arg_type extra_arg_name,Args&&... args) \ 224 { \ 225 return name_to(extra_arg_name,std::forward<Args>(args)...); \ 226 } 227 228 namespace boost{ 229 230 namespace multi_index{ 231 232 namespace detail{ 233 234 template<typename Value,typename... Args> 235 Value* vartempl_placement_new(Value*x,Args&&... args) 236 { 237 return new(x) Value(std::forward<Args>(args)...); 238 } 239 240 } /* namespace multi_index::detail */ 241 242 } /* namespace multi_index */ 243 244 } /* namespace boost */ 245 246 #endif 247 #endif 248