interface.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // (C) Copyright Tobias Schwinger
  2. //
  3. // Use modification and distribution are subject to the boost Software License,
  4. // Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
  5. //------------------------------------------------------------------------------
  6. //
  7. // This example implements interfaces.
  8. //
  9. // Detailed description
  10. // ====================
  11. //
  12. // An interface is a collection of member function prototypes that may be
  13. // implemented by classes. Objects of classes that implement the interface can
  14. // then be assigned to an interface variable through which the interface's
  15. // functions can be called.
  16. //
  17. // Interfaces are a feature of the Java programming language [Gosling] and the
  18. // most obvious way to model interfaces in C++ is (multiple) inheritance.
  19. // Using inheritance for this purpose, however, is neither the most efficient
  20. // nor the most flexible solution, because:
  21. //
  22. // - all functions must be virtual,
  23. //
  24. // => a function that calls another function of the interface must do so
  25. // via virtual dispatch (as opposed to inlining)
  26. // => a class can not implement an interface's (overloaded) function via
  27. // a function template
  28. //
  29. // - inhertitance is intrusive
  30. //
  31. // => object size increases
  32. // => client's are always polymorphic
  33. // => dependencies cause tighter coupling
  34. //
  35. // Fortunately it is possible to eliminate all the drawbacks mentioned above
  36. // based on an alternative implementation proposed by David Abrahams.
  37. // We'll add some detail to the original scheme (see [Abrahams]) such as
  38. // support for overloaded and const qualified functions.
  39. // The implementation in this example uses Boost.FunctionTypes to shift
  40. // metaprogramming code from the preprocessor into templates, to reduce
  41. // preprocessing time and increase maintainability.
  42. //
  43. //
  44. // Limitations
  45. // ===========
  46. //
  47. // There is no lifetime management as implemented by the Boost candidate
  48. // Interfaces library (see [Turkanis]).
  49. //
  50. // This example does not compile with Visual C++. Template argument deduction
  51. // from the result of the address-of operator does not work properly with this
  52. // compiler. It is possible to partially work around the problem, but it isn't
  53. // done here for the sake of readability.
  54. //
  55. //
  56. // Bibliography
  57. // ============
  58. //
  59. // [Gosling] Gosling, J., Joy, B., Steele, G. The Java Language Specification
  60. // http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html
  61. //
  62. // [Abrahams] Abrahams, D. Proposal: interfaces, Post to newsgroup comp.std.c++
  63. // http://groups.google.com/group/comp.std.c++/msg/85af30a61bf677e4
  64. //
  65. // [Turkanis] Turkanis, J., Diggins, C. Boost candidate Interfaces library
  66. // http://www.kangaroologic.com/interfaces/libs/interfaces/doc/index.html
  67. #include <cstddef>
  68. #include <boost/function_types/function_pointer.hpp>
  69. #include <boost/function_types/member_function_pointer.hpp>
  70. #include <boost/config.hpp>
  71. #include <boost/detail/workaround.hpp>
  72. #include <boost/utility/addressof.hpp>
  73. #include <boost/mpl/at.hpp>
  74. #include <boost/mpl/vector.hpp>
  75. #include <boost/mpl/joint_view.hpp>
  76. #include <boost/mpl/single_view.hpp>
  77. #include <boost/mpl/transform_view.hpp>
  78. #include <boost/preprocessor/seq/seq.hpp>
  79. #include <boost/preprocessor/seq/enum.hpp>
  80. #include <boost/preprocessor/seq/elem.hpp>
  81. #include <boost/preprocessor/seq/size.hpp>
  82. #include <boost/preprocessor/tuple/elem.hpp>
  83. #include <boost/preprocessor/arithmetic/dec.hpp>
  84. #include <boost/preprocessor/arithmetic/inc.hpp>
  85. #include <boost/preprocessor/facilities/empty.hpp>
  86. #include <boost/preprocessor/facilities/identity.hpp>
  87. #include <boost/preprocessor/punctuation/comma_if.hpp>
  88. #include <boost/preprocessor/iteration/local.hpp>
  89. #include <boost/preprocessor/repetition/enum.hpp>
  90. #include <boost/preprocessor/repetition/enum_params.hpp>
  91. #include <boost/preprocessor/repetition/enum_binary_params.hpp>
  92. #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
  93. #include "detail/param_type.hpp"
  94. namespace example
  95. {
  96. namespace ft = boost::function_types;
  97. namespace mpl = boost::mpl;
  98. using namespace mpl::placeholders;
  99. // join a single type and an MPL-sequence
  100. // in some ways similar to mpl::push_front (but mpl::push_front requires
  101. // an MPL Extensible Sequence and this template does not)
  102. template<typename T, typename Seq>
  103. struct concat_view
  104. : mpl::joint_view<mpl::single_view<T>, Seq>
  105. { };
  106. // metafunction returning a function pointer type for a vtable entry
  107. template<typename Inf>
  108. struct vtable_entry
  109. : ft::function_pointer
  110. < concat_view< typename Inf::result, mpl::transform_view<
  111. typename Inf::params, param_type<_> > > >
  112. { };
  113. // the expression '& member<MetaInfo,Tag>::wrap<& Class::Function> ' in an
  114. // assignment context binds the member function Function of Class with the
  115. // properties described by MetaInfo and Tag to the corresponding vtable
  116. // entry
  117. template<typename Inf, typename Tag>
  118. struct member
  119. {
  120. typedef typename ft::member_function_pointer
  121. < concat_view<typename Inf::result,typename Inf::params>,Tag
  122. >::type
  123. mem_func_ptr;
  124. typedef typename mpl::at_c<typename Inf::params,0>::type context;
  125. template<mem_func_ptr MemFuncPtr>
  126. static typename Inf::result wrap(void* c)
  127. {
  128. return (reinterpret_cast<context*>(c)->*MemFuncPtr)();
  129. }
  130. template<mem_func_ptr MemFuncPtr, typename T0>
  131. static typename Inf::result wrap(void* c, T0 a0)
  132. {
  133. return (reinterpret_cast<context*>(c)->*MemFuncPtr)(a0);
  134. }
  135. template<mem_func_ptr MemFuncPtr, typename T0, typename T1>
  136. static typename Inf::result wrap(void* c, T0 a0, T1 a1)
  137. {
  138. return (reinterpret_cast<context*>(c)->*MemFuncPtr)(a0,a1);
  139. }
  140. // continue with the preprocessor (the scheme should be clear, by now)
  141. #define BOOST_PP_LOCAL_MACRO(n) \
  142. template<mem_func_ptr MemFuncPtr, BOOST_PP_ENUM_PARAMS(n,typename T)> \
  143. static typename Inf::result wrap(void* c, \
  144. BOOST_PP_ENUM_BINARY_PARAMS(n,T,a)) \
  145. { \
  146. return (reinterpret_cast<context*>(c)->*MemFuncPtr)( \
  147. BOOST_PP_ENUM_PARAMS(n,a) ); \
  148. }
  149. #define BOOST_PP_LOCAL_LIMITS (3,BOOST_FT_MAX_ARITY-1)
  150. #include BOOST_PP_LOCAL_ITERATE()
  151. };
  152. // extract a parameter by index
  153. template<typename Inf, std::size_t Index>
  154. struct param
  155. : param_type< typename mpl::at_c< typename Inf::params,Index>::type >
  156. { };
  157. }
  158. // the interface definition on the client's side
  159. #define BOOST_EXAMPLE_INTERFACE(name,def) \
  160. class name \
  161. { \
  162. struct vtable \
  163. { \
  164. BOOST_EXAMPLE_INTERFACE__MEMBERS(def,VTABLE) \
  165. }; \
  166. \
  167. vtable const * ptr_vtable; \
  168. void * ptr_that; \
  169. \
  170. template<class T> struct vtable_holder \
  171. { \
  172. static vtable const val_vtable; \
  173. }; \
  174. \
  175. public: \
  176. \
  177. template<class T> \
  178. inline name (T & that) \
  179. : ptr_vtable(& vtable_holder<T>::val_vtable) \
  180. , ptr_that(boost::addressof(that)) \
  181. { } \
  182. \
  183. BOOST_EXAMPLE_INTERFACE__MEMBERS(def,FUNCTION) \
  184. }; \
  185. \
  186. template<typename T> \
  187. name ::vtable const name ::vtable_holder<T>::val_vtable \
  188. = { BOOST_EXAMPLE_INTERFACE__MEMBERS(def,INIT_VTABLE) }
  189. #ifdef BOOST_PP_NIL // never defined -- a comment with syntax highlighting
  190. BOOST_EXAMPLE_INTERFACE( interface_x,
  191. (( a_func, (void)(int), const_qualified ))
  192. (( another_func, (int), non_const ))
  193. );
  194. // expands to:
  195. class interface_x
  196. {
  197. struct vtable
  198. {
  199. // meta information for first function
  200. template<typename T = void*> struct inf0
  201. {
  202. typedef void result;
  203. typedef ::boost::mpl::vector< T, int > params;
  204. };
  205. // function pointer with void* context pointer and parameters optimized
  206. // for forwarding
  207. ::example::vtable_entry<inf0<> >::type func0;
  208. // second function
  209. template<typename T = void*> struct inf1
  210. {
  211. typedef int result;
  212. typedef ::boost::mpl::vector< T > params;
  213. };
  214. ::example::vtable_entry<inf1<> >::type func1;
  215. };
  216. // data members
  217. vtable const * ptr_vtable;
  218. void * ptr_that;
  219. // this template is instantiated for every class T this interface is created
  220. // from, causing the compiler to emit an initialized vtable for this type
  221. // (see aggregate assignment, below)
  222. template<class T> struct vtable_holder
  223. {
  224. static vtable const val_vtable;
  225. };
  226. public:
  227. // converting ctor, creates an interface from an arbitrary class
  228. template<class T>
  229. inline interface_x (T & that)
  230. : ptr_vtable(& vtable_holder<T>::val_vtable)
  231. , ptr_that(boost::addressof(that))
  232. { }
  233. // the member functions from the interface definition, parameters are
  234. // optimized for forwarding
  235. inline vtable::inf0<> ::result a_func (
  236. ::example::param<vtable::inf0<>,1>::type p0) const
  237. {
  238. return ptr_vtable-> func0(ptr_that , p0);
  239. }
  240. inline vtable::inf1<> ::result another_func ()
  241. {
  242. return ptr_vtable-> func1(ptr_that );
  243. }
  244. };
  245. template<typename T>
  246. interface_x ::vtable const interface_x ::vtable_holder<T>::val_vtable =
  247. {
  248. // instantiate function templates that wrap member function pointers (which
  249. // are known at compile time) by taking their addresses in assignment to
  250. // function pointer context
  251. & ::example::member< vtable::inf0<T>, ::example::ft:: const_qualified >
  252. ::template wrap < &T:: a_func >
  253. , & ::example::member< vtable::inf1<T>, ::example::ft:: non_const >
  254. ::template wrap < &T:: another_func >
  255. };
  256. #endif
  257. // preprocessing code details
  258. // iterate all of the interface's members and invoke a macro (prefixed with
  259. // BOOST_EXAMPLE_INTERFACE_)
  260. #define BOOST_EXAMPLE_INTERFACE__MEMBERS(seq,macro) \
  261. BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(seq), \
  262. BOOST_EXAMPLE_INTERFACE__ ## macro,seq)
  263. // extract signature sequence from entry
  264. #define BOOST_EXAMPLE_INTERFACE__VTABLE(z,i,seq) \
  265. BOOST_EXAMPLE_INTERFACE__VTABLE_I(z,i, \
  266. BOOST_PP_TUPLE_ELEM(3,1,BOOST_PP_SEQ_ELEM(i,seq)))
  267. // split the signature sequence result/params and insert T at the beginning of
  268. // the params part
  269. #define BOOST_EXAMPLE_INTERFACE__VTABLE_I(z,i,seq) \
  270. BOOST_EXAMPLE_INTERFACE__VTABLE_II(z,i, \
  271. BOOST_PP_SEQ_HEAD(seq),(T)BOOST_PP_SEQ_TAIL(seq))
  272. // emit the meta information structure and function pointer declaration
  273. #define BOOST_EXAMPLE_INTERFACE__VTABLE_II(z,i,result_type,param_types) \
  274. template<typename T = void*> \
  275. struct BOOST_PP_CAT(inf,i) \
  276. { \
  277. typedef result_type result; \
  278. typedef ::boost::mpl::vector< BOOST_PP_SEQ_ENUM(param_types) > params; \
  279. }; \
  280. ::example::vtable_entry<BOOST_PP_CAT(inf,i)<> >::type BOOST_PP_CAT(func,i);
  281. // extract tuple entry from sequence and precalculate the name of the function
  282. // pointer variable
  283. #define BOOST_EXAMPLE_INTERFACE__INIT_VTABLE(z,i,seq) \
  284. BOOST_EXAMPLE_INTERFACE__INIT_VTABLE_I(i,seq,BOOST_PP_CAT(func,i), \
  285. BOOST_PP_SEQ_ELEM(i,seq))
  286. // emit a function pointer expression that encapsulates the corresponding
  287. // member function of T
  288. #define BOOST_EXAMPLE_INTERFACE__INIT_VTABLE_I(i,seq,func,desc) \
  289. BOOST_PP_COMMA_IF(i) & ::example::member< BOOST_PP_CAT(vtable::inf,i)<T>, \
  290. ::example::ft:: BOOST_PP_TUPLE_ELEM(3,2,desc) >::template wrap \
  291. < &T:: BOOST_PP_TUPLE_ELEM(3,0,desc) >
  292. // extract tuple entry from sequence
  293. #define BOOST_EXAMPLE_INTERFACE__FUNCTION(z,i,seq) \
  294. BOOST_EXAMPLE_INTERFACE__FUNCTION_I(z,i,BOOST_PP_SEQ_ELEM(i,seq))
  295. // precalculate function name, arity, name of meta info structure and cv-
  296. // qualifiers
  297. #define BOOST_EXAMPLE_INTERFACE__FUNCTION_I(z,i,desc) \
  298. BOOST_EXAMPLE_INTERFACE__FUNCTION_II(z,i, \
  299. BOOST_PP_TUPLE_ELEM(3,0,desc), \
  300. BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3,1,desc))), \
  301. BOOST_PP_CAT(vtable::inf,i)<>, \
  302. BOOST_PP_CAT(BOOST_EXAMPLE_INTERFACE___,BOOST_PP_TUPLE_ELEM(3,2,desc)) \
  303. )
  304. // emit the definition for a member function of the interface
  305. #define BOOST_EXAMPLE_INTERFACE__FUNCTION_II(z,i,name,arity,types,cv) \
  306. inline types ::result name \
  307. (BOOST_PP_ENUM_ ## z (arity,BOOST_EXAMPLE_INTERFACE__PARAM,types)) cv() \
  308. { \
  309. return ptr_vtable-> BOOST_PP_CAT(func,i)(ptr_that \
  310. BOOST_PP_ENUM_TRAILING_PARAMS_Z(z,arity,p)); \
  311. }
  312. // emit a parameter of the function definition
  313. #define BOOST_EXAMPLE_INTERFACE__PARAM(z,j,types) \
  314. ::example::param<types,BOOST_PP_INC(j)>::type BOOST_PP_CAT(p,j)
  315. // helper macros to map 'const_qualified' to 'const' an 'non_const' to ''
  316. #define BOOST_EXAMPLE_INTERFACE___const_qualified BOOST_PP_IDENTITY(const)
  317. #define BOOST_EXAMPLE_INTERFACE___non_const BOOST_PP_EMPTY