signal_template.hpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. /*
  2. Template for Signa1, Signal2, ... classes that support signals
  3. with 1, 2, ... parameters
  4. Begin: 2007-01-23
  5. */
  6. // Copyright Frank Mori Hess 2007-2008
  7. //
  8. // Use, modification and
  9. // distribution is subject to the Boost Software License, Version
  10. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. // This file is included iteratively, and should not be protected from multiple inclusion
  13. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  14. #define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION()
  15. #else
  16. #define BOOST_SIGNALS2_NUM_ARGS 1
  17. #endif
  18. // R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
  19. #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \
  20. BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \
  21. Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
  22. namespace boost
  23. {
  24. namespace signals2
  25. {
  26. namespace detail
  27. {
  28. // helper for bound_extended_slot_function that handles specialization for void return
  29. template<typename R>
  30. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  31. {
  32. public:
  33. typedef R result_type;
  34. template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  35. BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  36. result_type operator()(ExtendedSlotFunction &func, const connection &conn
  37. BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  38. BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  39. {
  40. return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  41. BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
  42. }
  43. };
  44. #ifdef BOOST_NO_VOID_RETURNS
  45. template<>
  46. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void>
  47. {
  48. public:
  49. typedef result_type_wrapper<void>::type result_type;
  50. template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  51. BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  52. result_type operator()(ExtendedSlotFunction &func, const connection &conn
  53. BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  54. BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  55. {
  56. func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  57. BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
  58. return result_type();
  59. }
  60. };
  61. #endif
  62. // wrapper around an signalN::extended_slot_function which binds the
  63. // connection argument so it looks like a normal
  64. // signalN::slot_function
  65. template<typename ExtendedSlotFunction>
  66. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)
  67. {
  68. public:
  69. typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type;
  70. BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun):
  71. _fun(fun), _connection(new connection)
  72. {}
  73. void set_connection(const connection &conn)
  74. {
  75. *_connection = conn;
  76. }
  77. #if BOOST_SIGNALS2_NUM_ARGS > 0
  78. template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  79. #endif // BOOST_SIGNALS2_NUM_ARGS > 0
  80. result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  81. {
  82. return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  83. <typename ExtendedSlotFunction::result_type>()
  84. (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  85. BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
  86. }
  87. // const overload
  88. #if BOOST_SIGNALS2_NUM_ARGS > 0
  89. template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  90. #endif // BOOST_SIGNALS2_NUM_ARGS > 0
  91. result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  92. {
  93. return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  94. <typename ExtendedSlotFunction::result_type>()
  95. (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  96. BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS));
  97. }
  98. template<typename T>
  99. bool contains(const T &other) const
  100. {
  101. return _fun.contains(other);
  102. }
  103. private:
  104. BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)()
  105. {}
  106. ExtendedSlotFunction _fun;
  107. boost::shared_ptr<connection> _connection;
  108. };
  109. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  110. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  111. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  112. class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  113. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  114. class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
  115. {
  116. public:
  117. typedef SlotFunction slot_function_type;
  118. // typedef slotN<Signature, SlotFunction> slot_type;
  119. typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  120. <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS),
  121. slot_function_type> slot_type;
  122. typedef ExtendedSlotFunction extended_slot_function_type;
  123. // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type;
  124. typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type;
  125. typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type;
  126. private:
  127. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  128. class slot_invoker;
  129. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  130. typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker;
  131. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  132. typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type;
  133. typedef typename group_key<Group>::type group_key_type;
  134. typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type;
  135. typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
  136. typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type>
  137. bound_extended_slot_function_type;
  138. public:
  139. typedef Combiner combiner_type;
  140. typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type;
  141. typedef Group group_type;
  142. typedef GroupCompare group_compare_type;
  143. typedef typename detail::slot_call_iterator_t<slot_invoker,
  144. typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator;
  145. typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  146. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type;
  147. BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg,
  148. const group_compare_type &group_compare):
  149. _shared_state(boost::make_shared<invocation_state>(connection_list_type(group_compare), combiner_arg)),
  150. _garbage_collector_it(_shared_state->connection_bodies().end()),
  151. _mutex(new mutex_type())
  152. {}
  153. // connect slot
  154. connection connect(const slot_type &slot, connect_position position = at_back)
  155. {
  156. garbage_collecting_lock<mutex_type> lock(*_mutex);
  157. return nolock_connect(lock, slot, position);
  158. }
  159. connection connect(const group_type &group,
  160. const slot_type &slot, connect_position position = at_back)
  161. {
  162. garbage_collecting_lock<mutex_type> lock(*_mutex);
  163. return nolock_connect(lock, group, slot, position);
  164. }
  165. // connect extended slot
  166. connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back)
  167. {
  168. garbage_collecting_lock<mutex_type> lock(*_mutex);
  169. bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
  170. slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
  171. connection conn = nolock_connect(lock, slot, position);
  172. bound_slot.set_connection(conn);
  173. return conn;
  174. }
  175. connection connect_extended(const group_type &group,
  176. const extended_slot_type &ext_slot, connect_position position = at_back)
  177. {
  178. garbage_collecting_lock<Mutex> lock(*_mutex);
  179. bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
  180. slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
  181. connection conn = nolock_connect(lock, group, slot, position);
  182. bound_slot.set_connection(conn);
  183. return conn;
  184. }
  185. // disconnect slot(s)
  186. void disconnect_all_slots()
  187. {
  188. shared_ptr<invocation_state> local_state =
  189. get_readable_state();
  190. typename connection_list_type::iterator it;
  191. for(it = local_state->connection_bodies().begin();
  192. it != local_state->connection_bodies().end(); ++it)
  193. {
  194. (*it)->disconnect();
  195. }
  196. }
  197. void disconnect(const group_type &group)
  198. {
  199. shared_ptr<invocation_state> local_state =
  200. get_readable_state();
  201. group_key_type group_key(grouped_slots, group);
  202. typename connection_list_type::iterator it;
  203. typename connection_list_type::iterator end_it =
  204. local_state->connection_bodies().upper_bound(group_key);
  205. for(it = local_state->connection_bodies().lower_bound(group_key);
  206. it != end_it; ++it)
  207. {
  208. (*it)->disconnect();
  209. }
  210. }
  211. template <typename T>
  212. void disconnect(const T &slot)
  213. {
  214. typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
  215. do_disconnect(unwrap_ref(slot), is_group());
  216. }
  217. // emit signal
  218. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  219. {
  220. shared_ptr<invocation_state> local_state;
  221. typename connection_list_type::iterator it;
  222. {
  223. garbage_collecting_lock<mutex_type> list_lock(*_mutex);
  224. // only clean up if it is safe to do so
  225. if(_shared_state.unique())
  226. nolock_cleanup_connections(list_lock, false, 1);
  227. /* Make a local copy of _shared_state while holding mutex, so we are
  228. thread safe against the combiner or connection list getting modified
  229. during invocation. */
  230. local_state = _shared_state;
  231. }
  232. slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  233. slot_call_iterator_cache_type cache(invoker);
  234. invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
  235. return detail::combiner_invoker<typename combiner_type::result_type>()
  236. (
  237. local_state->combiner(),
  238. slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
  239. slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
  240. );
  241. }
  242. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  243. {
  244. shared_ptr<invocation_state> local_state;
  245. typename connection_list_type::iterator it;
  246. {
  247. garbage_collecting_lock<mutex_type> list_lock(*_mutex);
  248. // only clean up if it is safe to do so
  249. if(_shared_state.unique())
  250. nolock_cleanup_connections(list_lock, false, 1);
  251. /* Make a local copy of _shared_state while holding mutex, so we are
  252. thread safe against the combiner or connection list getting modified
  253. during invocation. */
  254. local_state = _shared_state;
  255. }
  256. slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  257. slot_call_iterator_cache_type cache(invoker);
  258. invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
  259. return detail::combiner_invoker<typename combiner_type::result_type>()
  260. (
  261. local_state->combiner(),
  262. slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
  263. slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
  264. );
  265. }
  266. std::size_t num_slots() const
  267. {
  268. shared_ptr<invocation_state> local_state =
  269. get_readable_state();
  270. typename connection_list_type::iterator it;
  271. std::size_t count = 0;
  272. for(it = local_state->connection_bodies().begin();
  273. it != local_state->connection_bodies().end(); ++it)
  274. {
  275. if((*it)->connected()) ++count;
  276. }
  277. return count;
  278. }
  279. bool empty() const
  280. {
  281. shared_ptr<invocation_state> local_state =
  282. get_readable_state();
  283. typename connection_list_type::iterator it;
  284. for(it = local_state->connection_bodies().begin();
  285. it != local_state->connection_bodies().end(); ++it)
  286. {
  287. if((*it)->connected()) return false;
  288. }
  289. return true;
  290. }
  291. combiner_type combiner() const
  292. {
  293. unique_lock<mutex_type> lock(*_mutex);
  294. return _shared_state->combiner();
  295. }
  296. void set_combiner(const combiner_type &combiner_arg)
  297. {
  298. unique_lock<mutex_type> lock(*_mutex);
  299. if(_shared_state.unique())
  300. _shared_state->combiner() = combiner_arg;
  301. else
  302. _shared_state = boost::make_shared<invocation_state>(*_shared_state, combiner_arg);
  303. }
  304. private:
  305. typedef Mutex mutex_type;
  306. // slot_invoker is passed to slot_call_iterator_t to run slots
  307. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  308. class slot_invoker
  309. {
  310. public:
  311. typedef nonvoid_slot_result_type result_type;
  312. // typename add_reference<Tn>::type
  313. #define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \
  314. typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type
  315. // typename add_reference<Tn>::type argn
  316. #define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \
  317. BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \
  318. BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~)
  319. // typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn
  320. #define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \
  321. BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~)
  322. slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :)
  323. #undef BOOST_SIGNALS2_ADD_REF_ARGS
  324. // m_argn
  325. #define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n))
  326. // m_argn ( argn )
  327. #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
  328. BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) )
  329. // m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn)
  330. BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
  331. #undef BOOST_SIGNALS2_MISC_STATEMENT
  332. {}
  333. result_type operator ()(const connection_body_type &connectionBody) const
  334. {
  335. return m_invoke<typename slot_type::result_type>(connectionBody);
  336. }
  337. private:
  338. // declare assignment operator private since this class might have reference or const members
  339. slot_invoker & operator=(const slot_invoker &);
  340. #define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \
  341. BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ;
  342. BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~)
  343. #undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT
  344. #undef BOOST_SIGNALS2_ADD_REF_ARG
  345. #undef BOOST_SIGNALS2_ADD_REF_TYPE
  346. // m_arg1, m_arg2, ..., m_argn
  347. #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~)
  348. template<typename SlotResultType>
  349. result_type m_invoke(const connection_body_type &connectionBody,
  350. typename boost::enable_if<boost::is_void<SlotResultType> >::type * = 0) const
  351. {
  352. connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  353. return void_type();
  354. }
  355. template<typename SlotResultType>
  356. result_type m_invoke(const connection_body_type &connectionBody,
  357. typename boost::disable_if<boost::is_void<SlotResultType> >::type * = 0) const
  358. {
  359. return connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  360. }
  361. };
  362. #undef BOOST_SIGNALS2_M_ARG_NAMES
  363. #undef BOOST_SIGNALS2_M_ARG_NAME
  364. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  365. // a struct used to optimize (minimize) the number of shared_ptrs that need to be created
  366. // inside operator()
  367. class invocation_state
  368. {
  369. public:
  370. invocation_state(const connection_list_type &connections_in,
  371. const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)),
  372. _combiner(new combiner_type(combiner_in))
  373. {}
  374. invocation_state(const invocation_state &other, const connection_list_type &connections_in):
  375. _connection_bodies(new connection_list_type(connections_in)),
  376. _combiner(other._combiner)
  377. {}
  378. invocation_state(const invocation_state &other, const combiner_type &combiner_in):
  379. _connection_bodies(other._connection_bodies),
  380. _combiner(new combiner_type(combiner_in))
  381. {}
  382. connection_list_type & connection_bodies() { return *_connection_bodies; }
  383. const connection_list_type & connection_bodies() const { return *_connection_bodies; }
  384. combiner_type & combiner() { return *_combiner; }
  385. const combiner_type & combiner() const { return *_combiner; }
  386. private:
  387. invocation_state(const invocation_state &);
  388. shared_ptr<connection_list_type> _connection_bodies;
  389. shared_ptr<combiner_type> _combiner;
  390. };
  391. // Destructor of invocation_janitor does some cleanup when a signal invocation completes.
  392. // Code can't be put directly in signal's operator() due to complications from void return types.
  393. class invocation_janitor: noncopyable
  394. {
  395. public:
  396. typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type;
  397. invocation_janitor
  398. (
  399. const slot_call_iterator_cache_type &cache,
  400. const signal_type &sig,
  401. const connection_list_type *connection_bodies
  402. ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies)
  403. {}
  404. ~invocation_janitor()
  405. {
  406. // force a full cleanup of disconnected slots if there are too many
  407. if(_cache.disconnected_slot_count > _cache.connected_slot_count)
  408. {
  409. _sig.force_cleanup_connections(_connection_bodies);
  410. }
  411. }
  412. private:
  413. const slot_call_iterator_cache_type &_cache;
  414. const signal_type &_sig;
  415. const connection_list_type *_connection_bodies;
  416. };
  417. // clean up disconnected connections
  418. void nolock_cleanup_connections_from(garbage_collecting_lock<mutex_type> &lock,
  419. bool grab_tracked,
  420. const typename connection_list_type::iterator &begin, unsigned count = 0) const
  421. {
  422. BOOST_ASSERT(_shared_state.unique());
  423. typename connection_list_type::iterator it;
  424. unsigned i;
  425. for(it = begin, i = 0;
  426. it != _shared_state->connection_bodies().end() && (count == 0 || i < count);
  427. ++i)
  428. {
  429. bool connected;
  430. if(grab_tracked)
  431. (*it)->disconnect_expired_slot(lock);
  432. connected = (*it)->nolock_nograb_connected();
  433. if(connected == false)
  434. {
  435. it = _shared_state->connection_bodies().erase((*it)->group_key(), it);
  436. }else
  437. {
  438. ++it;
  439. }
  440. }
  441. _garbage_collector_it = it;
  442. }
  443. // clean up a few connections in constant time
  444. void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock,
  445. bool grab_tracked, unsigned count) const
  446. {
  447. BOOST_ASSERT(_shared_state.unique());
  448. typename connection_list_type::iterator begin;
  449. if(_garbage_collector_it == _shared_state->connection_bodies().end())
  450. {
  451. begin = _shared_state->connection_bodies().begin();
  452. }else
  453. {
  454. begin = _garbage_collector_it;
  455. }
  456. nolock_cleanup_connections_from(lock, grab_tracked, begin, count);
  457. }
  458. /* Make a new copy of the slot list if it is currently being read somewhere else
  459. */
  460. void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock)
  461. {
  462. if(_shared_state.unique() == false)
  463. {
  464. _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
  465. nolock_cleanup_connections_from(lock, true, _shared_state->connection_bodies().begin());
  466. }else
  467. {
  468. /* We need to try and check more than just 1 connection here to avoid corner
  469. cases where certain repeated connect/disconnect patterns cause the slot
  470. list to grow without limit. */
  471. nolock_cleanup_connections(lock, true, 2);
  472. }
  473. }
  474. // force a full cleanup of the connection list
  475. void force_cleanup_connections(const connection_list_type *connection_bodies) const
  476. {
  477. garbage_collecting_lock<mutex_type> list_lock(*_mutex);
  478. // if the connection list passed in as a parameter is no longer in use,
  479. // we don't need to do any cleanup.
  480. if(&_shared_state->connection_bodies() != connection_bodies)
  481. {
  482. return;
  483. }
  484. if(_shared_state.unique() == false)
  485. {
  486. _shared_state = boost::make_shared<invocation_state>(*_shared_state, _shared_state->connection_bodies());
  487. }
  488. nolock_cleanup_connections_from(list_lock, false, _shared_state->connection_bodies().begin());
  489. }
  490. shared_ptr<invocation_state> get_readable_state() const
  491. {
  492. unique_lock<mutex_type> list_lock(*_mutex);
  493. return _shared_state;
  494. }
  495. connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock,
  496. const slot_type &slot)
  497. {
  498. nolock_force_unique_connection_list(lock);
  499. return boost::make_shared<connection_body<group_key_type, slot_type, Mutex> >(slot, _mutex);
  500. }
  501. void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */)
  502. {
  503. disconnect(group);
  504. }
  505. template<typename T>
  506. void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
  507. {
  508. shared_ptr<invocation_state> local_state =
  509. get_readable_state();
  510. typename connection_list_type::iterator it;
  511. for(it = local_state->connection_bodies().begin();
  512. it != local_state->connection_bodies().end(); ++it)
  513. {
  514. garbage_collecting_lock<connection_body_base> lock(**it);
  515. if((*it)->nolock_nograb_connected() == false) continue;
  516. if((*it)->slot().slot_function().contains(slot))
  517. {
  518. (*it)->nolock_disconnect(lock);
  519. }else
  520. { // check for wrapped extended slot
  521. bound_extended_slot_function_type *fp;
  522. fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>();
  523. if(fp && fp->contains(slot))
  524. {
  525. (*it)->nolock_disconnect(lock);
  526. }else
  527. { // check for wrapped signal
  528. weak_signal_type *fp;
  529. fp = (*it)->slot().slot_function().template target<weak_signal_type>();
  530. if(fp && fp->contains(slot))
  531. {
  532. (*it)->nolock_disconnect(lock);
  533. }
  534. }
  535. }
  536. }
  537. }
  538. // connect slot
  539. connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
  540. const slot_type &slot, connect_position position)
  541. {
  542. connection_body_type newConnectionBody =
  543. create_new_connection(lock, slot);
  544. group_key_type group_key;
  545. if(position == at_back)
  546. {
  547. group_key.first = back_ungrouped_slots;
  548. _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
  549. }else
  550. {
  551. group_key.first = front_ungrouped_slots;
  552. _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
  553. }
  554. newConnectionBody->set_group_key(group_key);
  555. return connection(newConnectionBody);
  556. }
  557. connection nolock_connect(garbage_collecting_lock<mutex_type> &lock,
  558. const group_type &group,
  559. const slot_type &slot, connect_position position)
  560. {
  561. connection_body_type newConnectionBody =
  562. create_new_connection(lock, slot);
  563. // update map to first connection body in group if needed
  564. group_key_type group_key(grouped_slots, group);
  565. newConnectionBody->set_group_key(group_key);
  566. if(position == at_back)
  567. {
  568. _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
  569. }else // at_front
  570. {
  571. _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
  572. }
  573. return connection(newConnectionBody);
  574. }
  575. // _shared_state is mutable so we can do force_cleanup_connections during a const invocation
  576. mutable shared_ptr<invocation_state> _shared_state;
  577. mutable typename connection_list_type::iterator _garbage_collector_it;
  578. // connection list mutex must never be locked when attempting a blocking lock on a slot,
  579. // or you could deadlock.
  580. const boost::shared_ptr<mutex_type> _mutex;
  581. };
  582. }
  583. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  584. class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  585. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  586. class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  587. BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base,
  588. public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE
  589. {
  590. typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  591. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class;
  592. public:
  593. typedef typename impl_class::weak_signal_type weak_signal_type;
  594. friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  595. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>;
  596. typedef SlotFunction slot_function_type;
  597. // typedef slotN<Signature, SlotFunction> slot_type;
  598. typedef typename impl_class::slot_type slot_type;
  599. typedef typename impl_class::extended_slot_function_type extended_slot_function_type;
  600. typedef typename impl_class::extended_slot_type extended_slot_type;
  601. typedef typename slot_function_type::result_type slot_result_type;
  602. typedef Combiner combiner_type;
  603. typedef typename impl_class::result_type result_type;
  604. typedef Group group_type;
  605. typedef GroupCompare group_compare_type;
  606. typedef typename impl_class::slot_call_iterator
  607. slot_call_iterator;
  608. typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type;
  609. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  610. // typedef Tn argn_type;
  611. #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
  612. typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
  613. BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
  614. #undef BOOST_SIGNALS2_MISC_STATEMENT
  615. #if BOOST_SIGNALS2_NUM_ARGS == 1
  616. typedef arg1_type argument_type;
  617. #elif BOOST_SIGNALS2_NUM_ARGS == 2
  618. typedef arg1_type first_argument_type;
  619. typedef arg2_type second_argument_type;
  620. #endif
  621. template<unsigned n> class arg : public
  622. detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  623. <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  624. BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)>
  625. {};
  626. BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS);
  627. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  628. template<unsigned n> class arg
  629. {
  630. public:
  631. typedef typename detail::variadic_arg_type<n, Args...>::type type;
  632. };
  633. BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args));
  634. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  635. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(),
  636. const group_compare_type &group_compare = group_compare_type()):
  637. _pimpl(new impl_class(combiner_arg, group_compare))
  638. {}
  639. virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)()
  640. {
  641. }
  642. //move support
  643. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  644. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
  645. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && other) BOOST_NOEXCEPT
  646. {
  647. using std::swap;
  648. swap(_pimpl, other._pimpl);
  649. }
  650. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) &
  651. operator=(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && rhs) BOOST_NOEXCEPT
  652. {
  653. if(this == &rhs)
  654. {
  655. return *this;
  656. }
  657. _pimpl.reset();
  658. using std::swap;
  659. swap(_pimpl, rhs._pimpl);
  660. return *this;
  661. }
  662. #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  663. connection connect(const slot_type &slot, connect_position position = at_back)
  664. {
  665. return (*_pimpl).connect(slot, position);
  666. }
  667. connection connect(const group_type &group,
  668. const slot_type &slot, connect_position position = at_back)
  669. {
  670. return (*_pimpl).connect(group, slot, position);
  671. }
  672. connection connect_extended(const extended_slot_type &slot, connect_position position = at_back)
  673. {
  674. return (*_pimpl).connect_extended(slot, position);
  675. }
  676. connection connect_extended(const group_type &group,
  677. const extended_slot_type &slot, connect_position position = at_back)
  678. {
  679. return (*_pimpl).connect_extended(group, slot, position);
  680. }
  681. void disconnect_all_slots()
  682. {
  683. if (_pimpl.get() == 0) return;
  684. (*_pimpl).disconnect_all_slots();
  685. }
  686. void disconnect(const group_type &group)
  687. {
  688. if (_pimpl.get() == 0) return;
  689. (*_pimpl).disconnect(group);
  690. }
  691. template <typename T>
  692. void disconnect(const T &slot)
  693. {
  694. if (_pimpl.get() == 0) return;
  695. (*_pimpl).disconnect(slot);
  696. }
  697. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  698. {
  699. return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  700. }
  701. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  702. {
  703. return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  704. }
  705. std::size_t num_slots() const
  706. {
  707. if (_pimpl.get() == 0) return 0;
  708. return (*_pimpl).num_slots();
  709. }
  710. bool empty() const
  711. {
  712. if (_pimpl.get() == 0) return true;
  713. return (*_pimpl).empty();
  714. }
  715. combiner_type combiner() const
  716. {
  717. return (*_pimpl).combiner();
  718. }
  719. void set_combiner(const combiner_type &combiner_arg)
  720. {
  721. return (*_pimpl).set_combiner(combiner_arg);
  722. }
  723. void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT
  724. {
  725. using std::swap;
  726. swap(_pimpl, other._pimpl);
  727. }
  728. bool operator==(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) const
  729. {
  730. return _pimpl.get() == other._pimpl.get();
  731. }
  732. bool null() const
  733. {
  734. return _pimpl.get() == 0;
  735. }
  736. protected:
  737. virtual shared_ptr<void> lock_pimpl() const
  738. {
  739. return _pimpl;
  740. }
  741. private:
  742. // explicit private copy constructor to avoid compiler trying to do implicit conversions to signal
  743. explicit BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(
  744. const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT
  745. {
  746. // noncopyable
  747. BOOST_ASSERT(false);
  748. }
  749. shared_ptr<impl_class>
  750. _pimpl;
  751. };
  752. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  753. // free swap function for signalN classes, findable by ADL
  754. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  755. void swap(
  756. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1,
  757. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) BOOST_NOEXCEPT
  758. {
  759. sig1.swap(sig2);
  760. }
  761. #endif
  762. namespace detail
  763. {
  764. // wrapper class for storing other signals as slots with automatic lifetime tracking
  765. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  766. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  767. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  768. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  769. BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
  770. {
  771. public:
  772. typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  773. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type
  774. result_type;
  775. BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  776. (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  777. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>
  778. &signal):
  779. _weak_pimpl(signal._pimpl)
  780. {}
  781. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  782. {
  783. shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  784. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
  785. shared_pimpl(_weak_pimpl.lock());
  786. return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  787. }
  788. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  789. {
  790. shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  791. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
  792. shared_pimpl(_weak_pimpl.lock());
  793. return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  794. }
  795. bool contains(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  796. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &signal) const
  797. {
  798. return _weak_pimpl.lock().get() == signal._pimpl.get();
  799. }
  800. template <typename T>
  801. bool contains(const T&) const
  802. {
  803. return false;
  804. }
  805. private:
  806. boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  807. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl;
  808. };
  809. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  810. template<int arity, typename Signature>
  811. class extended_signature: public variadic_extended_signature<Signature>
  812. {};
  813. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  814. template<int arity, typename Signature>
  815. class extended_signature;
  816. // partial template specialization
  817. template<typename Signature>
  818. class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature>
  819. {
  820. public:
  821. // typename function_traits<Signature>::result_type (
  822. // const boost::signals2::connection &,
  823. // typename function_traits<Signature>::arg1_type,
  824. // typename function_traits<Signature>::arg2_type,
  825. // ...,
  826. // typename function_traits<Signature>::argn_type)
  827. #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \
  828. typename function_traits<Signature>::result_type ( \
  829. const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \
  830. BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) )
  831. typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type;
  832. #undef BOOST_SIGNALS2_EXT_SIGNATURE
  833. };
  834. template<unsigned arity, typename Signature, typename Combiner,
  835. typename Group, typename GroupCompare, typename SlotFunction,
  836. typename ExtendedSlotFunction, typename Mutex>
  837. class signalN;
  838. // partial template specialization
  839. template<typename Signature, typename Combiner, typename Group,
  840. typename GroupCompare, typename SlotFunction,
  841. typename ExtendedSlotFunction, typename Mutex>
  842. class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group,
  843. GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex>
  844. {
  845. public:
  846. typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)<
  847. BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature),
  848. Combiner, Group,
  849. GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type;
  850. };
  851. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  852. } // namespace detail
  853. } // namespace signals2
  854. } // namespace boost
  855. #undef BOOST_SIGNALS2_NUM_ARGS
  856. #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION