123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- [library Boost.TypeErasure
- [quickbook 1.5]
- [authors [Watanabe, Steven]]
- [copyright 2011-2013 Steven Watanabe]
- [license
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- [@http://www.boost.org/LICENSE_1_0.txt])
- ]
- [purpose Runtime polymorphism based on concepts]
- ]
- [def __any [classref boost::type_erasure::any any]]
- [def __any_cast [funcref boost::type_erasure::any_cast any_cast]]
- [def __tuple [classref boost::type_erasure::tuple tuple]]
- [def __rebind_any [classref boost::type_erasure::rebind_any rebind_any]]
- [def __derived [classref boost::type_erasure::derived derived]]
- [def __concept_interface [classref boost::type_erasure::concept_interface concept_interface]]
- [def __constructible [classref boost::type_erasure::constructible constructible]]
- [def __destructible [classref boost::type_erasure::destructible destructible]]
- [def __copy_constructible [classref boost::type_erasure::copy_constructible copy_constructible]]
- [def __assignable [classref boost::type_erasure::assignable assignable]]
- [def __typeid_ [classref boost::type_erasure::typeid_ typeid_]]
- [def __relaxed [classref boost::type_erasure::relaxed relaxed]]
- [def __binding [classref boost::type_erasure::binding binding]]
- [def __static_binding [classref boost::type_erasure::static_binding static_binding]]
- [def __placeholder [classref boost::type_erasure::placeholder placeholder]]
- [def __call [funcref boost::type_erasure::call call]]
- [def __deduced [classref boost::type_erasure::deduced deduced]]
- [def __as_param [classref boost::type_erasure::as_param as_param]]
- [def __addable [classref boost::type_erasure::addable addable]]
- [def __subtractable [classref boost::type_erasure::subtractable subtractable]]
- [def __multipliable [classref boost::type_erasure::multipliable multipliable]]
- [def __dividable [classref boost::type_erasure::dividable dividable]]
- [def __modable [classref boost::type_erasure::modable modable]]
- [def __bitandable [classref boost::type_erasure::bitandable bitandable]]
- [def __bitorable [classref boost::type_erasure::bitorable bitorable]]
- [def __bitxorable [classref boost::type_erasure::bitxorable bitxorable]]
- [def __left_shiftable [classref boost::type_erasure::left_shiftable left_shiftable]]
- [def __right_shiftable [classref boost::type_erasure::right_shiftable right_shiftable]]
- [def __add_assignable [classref boost::type_erasure::add_assignable add_assignable]]
- [def __subtract_assignable [classref boost::type_erasure::subtract_assignable subtract_assignable]]
- [def __multiply_assignable [classref boost::type_erasure::multiply_assignable multiply_assignable]]
- [def __divide_assignable [classref boost::type_erasure::divide_assignable divide_assignable]]
- [def __mod_assignable [classref boost::type_erasure::mod_assignable mod_assignable]]
- [def __bitand_assignable [classref boost::type_erasure::bitand_assignable bitand_assignable]]
- [def __bitor_assignable [classref boost::type_erasure::bitor_assignable bitor_assignable]]
- [def __bitxor_assignable [classref boost::type_erasure::bitxor_assignable bitxor_assignable]]
- [def __left_shift_assignable [classref boost::type_erasure::left_shift_assignable left_shift_assignable]]
- [def __right_shift_assignable [classref boost::type_erasure::right_shift_assignable right_shift_assignable]]
- [def __incrementable [classref boost::type_erasure::incrementable incrementable]]
- [def __decrementable [classref boost::type_erasure::decrementable decrementable]]
- [def __negatable [classref boost::type_erasure::negatable negatable]]
- [def __complementable [classref boost::type_erasure::complementable complementable]]
- [def __dereferenceable [classref boost::type_erasure::dereferenceable dereferenceable]]
- [def __callable [classref boost::type_erasure::callable callable]]
- [def __subscriptable [classref boost::type_erasure::subscriptable subscriptable]]
- [def __equality_comparable [classref boost::type_erasure::equality_comparable equality_comparable]]
- [def __less_than_comparable [classref boost::type_erasure::less_than_comparable less_than_comparable]]
- [def __ostreamable [classref boost::type_erasure::ostreamable ostreamable]]
- [def __istreamable [classref boost::type_erasure::istreamable istreamable]]
- [def __iterator [classref boost::type_erasure::iterator iterator]]
- [def __forward_iterator [classref boost::type_erasure::forward_iterator forward_iterator]]
- [def __bidirectional_iterator [classref boost::type_erasure::bidirectional_iterator bidirectional_iterator]]
- [def __random_access_iterator [classref boost::type_erasure::random_access_iterator random_access_iterator]]
- [def __same_type [classref boost::type_erasure::same_type same_type]]
- [def __BOOST_TYPE_ERASURE_MEMBER [macroref BOOST_TYPE_ERASURE_MEMBER]]
- [def __BOOST_TYPE_ERASURE_FREE [macroref BOOST_TYPE_ERASURE_FREE]]
- [section:introduction Introduction]
- The Boost.TypeErasure library provides runtime polymorphism
- in C++ that is more flexible than that provided by the
- core language.
- C++ has two distinct kinds of polymorphism,
- virtual functions and templates, each of which has
- its own advantages and disadvantages.
- * Virtual functions are not resolved until runtime,
- while templates are always resolved at compile
- time. If your types can vary at runtime (for
- example, if they depend on user input), then
- static polymorphism with templates doesn't help much.
- * Virtual functions can be used with separate compilation.
- The body of a template has to be available
- in every translation unit in which it is used,
- slowing down compiles and increasing rebuilds.
- * Virtual functions automatically make the requirements
- on the arguments explicit. Templates are only
- checked when they're instantiated, requiring
- extra work in testing, assertions, and documentation.
- * The compiler creates a new copy of each function
- template every time it is instantiated. This
- allows better optimization, because the compiler
- knows everything statically, but it also causes
- a significant increase of binary sizes.
- * Templates support Value semantics. Objects that
- "behave like an int" and are not shared are easier
- to reason about. To use virtual functions, on
- the other hand, you have to use (smart) pointers
- or references.
- * Template libraries can allow third-party types to
- be adapted non-intrusively for seamless interoperability.
- With virtual functions, you have to create a wrapper
- that inherits from the base class.
- * Templates can handle constraints involving
- multiple types. For example, std::for_each
- takes an iterator range and a function that
- can be called on the elements of the range.
- Virtual functions aren't really able to
- express such constraints.
- The Boost.TypeErasure library combines the superior
- abstraction capabilities of templates, with the
- runtime flexibility of virtual functions.
- Boost includes several special cases of this kind
- of polymorphism:
- * `boost::any` for CopyConstructible types.
- * `boost::function` for objects that can be called like functions.
- * Boost.Range provides `any_iterator`.
- Boost.TypeErasure generalizes this to support arbitrary
- requirements and provides a
- [link boost_typeerasure.predef predefined set of common concepts]
- [endsect]
- [section:reading How to read this documentation]
- To avoid excessive verbosity, all the examples
- assume that a few using directives are in place.
- namespace mpl = boost::mpl;
- using namespace boost::type_erasure;
- [endsect]
- [section:basic Basic Usage]
- [import ../example/basic.cpp]
- [basic]
- [endsect]
- [section Composing Concepts]
- [import ../example/compose.cpp]
- [compose]
- [endsect]
- [section:multi Functions with Multiple Arguments]
- [import ../example/multi.cpp]
- [multi]
- [endsect]
- [section:concept Concepts in Depth]
- [section:custom Defining Custom Concepts]
- [import ../example/custom.cpp]
- [custom]
- [endsect]
- [section:overload Overloading]
- [import ../example/overload.cpp]
- [overload]
- [endsect]
- [section:concept_map Concept Maps]
- [import ../example/concept_map.cpp]
- [concept_map]
- [endsect]
- [section:overload Associated Types]
- [import ../example/associated.cpp]
- [associated]
- [endsect]
- [endsect]
- [section:any Using Any]
- [section:construction Construction]
- [import ../example/construction.cpp]
- [construction]
- [endsect]
- [section Conversions]
- [import ../example/convert.cpp]
- [convert]
- [endsect]
- [section:references References]
- [import ../example/references.cpp]
- [references]
- [endsect]
- [section:limit Syntax Limitations]
- In most cases using an any has the same
- syntax as using the underlying object.
- However, there are a few cases where
- this is not possible to implement.
- An __any reference is proxy and cannot
- be used in contexts where a real
- reference is required. In particular,
- __forward_iterator does not create
- a conforming ForwardIterator (unless
- the value_type is fixed.) Another
- difference is that all operations
- which do not take at least one __any
- argument have to be passed the type
- information explicitly. Static member
- functions and constructors can fall in
- this category. All this means that generic
- algorithms might not work when applied to
- __any arguments.
- [endsect]
- [endsect]
- [section:examples Examples]
- [section:print_sequence A polymorphic range formatter]
- [import ../example/print_sequence.cpp]
- [print_sequence]
- [endsect]
- [section:printf A type-safe printf]
- [import ../example/printf.cpp]
- [printf]
- [endsect]
- [section:multifunction Boost.Function with multiple signatures]
- [import ../example/multifunction.cpp]
- [multifunction]
- [endsect]
- [endsect]
- [section:conceptdef Concept Definitions]
- A Concept defines a set of constraints on the types that
- are stored in an __any.
- There are three kinds of concepts.
- # The library defines a number of [link boost_typeerasure.predef predefined concepts].
- Most of these are equivalent to user-defined concepts, but a few
- require special handling.
- # Users can define their own primitive concepts as described below.
- The macros __BOOST_TYPE_ERASURE_MEMBER and __BOOST_TYPE_ERASURE_FREE
- define concepts of this form.
- # Any MPL Forward Sequence whose elements are
- concepts is also a concept. This allows concepts
- to be composed easily.
- Each primitive concept defines a single function.
- A primitive concept must be a specialization of a
- class template, with a static member function
- called `apply`, which will be executed when the
- function is dispatched by __call. The template
- can only take template type parameters. non-type
- template parameters and template template parameters
- are not allowed.
- The template parameters of the concept
- may involve placeholders. The following are
- considered.
- * Each template argument may be a cv and/or reference
- qualified placeholder type.
- * If a template argument is a function type, its
- arguments and return type may be cv/reference
- qualified placeholders.
- Any other placeholders are ignored.
- A concept is instantiated by constructing an
- __any from a raw value or by constructing a __binding.
- When a concept is instantiated with a specific
- set of type bindings, each placeholder is bound
- to a cv-unqualified non-reference type. After
- replacing each placeholder in the template argument
- list with the type that it binds to, the following
- must hold.
- * The number of arguments of apply in the
- bound concept must be the same as the number
- of arguments in the unbound concept.
- * The arguments and return type of apply in the
- bound concept can be derived from the corresponding
- arguments and the return type in the unbound concept
- as follows: If the argument in the unbound concept is a
- placeholder with optional cv and reference
- qualifiers, then the argument in the bound
- concept can be found by replacing the placeholder.
- Otherwise, the argument in the unbound concept
- must be the same as the argument in the bound concept.
- // Correct.
- template<class T = _self>
- struct foo1 {
- static void apply(const T& t) { t.foo(); }
- };
- // Wrong. The signature of apply is different from the
- // primary template
- template<>
- struct foo1<int> {
- static void apply(int i);
- };
- // Wrong. A concept must be a template
- struct foo2 {
- static void apply(const _self&);
- };
- // Wrong. apply must be static
- template<class T = _self>
- struct foo3 {
- void apply(const T&);
- };
- // Wrong. apply cannot be overloaded
- template<class T = _self>
- struct foo3 {
- static void apply(T&);
- static void apply(const T&);
- };
- // Wrong. Only top level placeholders are detected
- template<class T>
- struct foo4;
- template<class T>
- struct foo4<boost::mpl::vector<T> > {
- static void apply(const T&);
- };
- // Wrong. Template template parameters are not allowed.
- template<template<class> class T>
- struct foo5
- {
- static void apply(T<int>&);
- };
- [endsect]
- [section:predef Predefined Concepts]
- In the following tables, `T` and `U` are the types that the operation
- applies to, `R` is the result type. `T` always defaults
- to `_self` to match the default behavior of any. These
- concepts assume normal semantics. Thus, comparison
- operators always return bool, and references will be
- added to the arguments and results as appropriate.
- Except as otherwise noted, primitive concepts defined by
- the library can be specialized to provide concept maps.
- __copy_constructible, and the iterator concepts cannot
- be specialized because they are composites. __constructible,
- __destructible, __typeid_, and __same_type cannot be
- specialized because they require special handling in
- the library.
- [table:special Special Members
- [[concept][notes]]
- [[__constructible`<Sig>`][-]]
- [[__copy_constructible`<T>`][-]]
- [[__destructible`<T>`][-]]
- [[__assignable`<T, U = const T&>`][-]]
- [[__typeid_`<T>`][-]]
- ]
- [table:unary Unary Operators
- [[operator][concept][notes]]
- [[`operator++`][__incrementable`<T>`][There is no separate post-increment]]
- [[`operator--`][__decrementable`<T>`][There is no separate post-decrement]]
- [[`operator*`][__dereferenceable`<R, T>`][`R` should usually be a reference]]
- [[`operator~`][__complementable`<T, R = T>`][-]]
- [[`operator-`][__negatable`<T, R = T>`][-]]
- ]
- [table:binary Binary Operators
- [[operator][concept][notes]]
- [[`operator+`][__addable`<T, U = T, R = T>`][-]]
- [[`operator-`][__subtractable`<T, U = T, R = T>`][-]]
- [[`operator*`][__multipliable`<T, U = T, R = T>`][-]]
- [[`operator/`][__dividable`<T, U = T, R = T>`][-]]
- [[`operator%`][__modable`<T, U = T, R = T>`][-]]
- [[`operator&`][__bitandable`<T, U = T, R = T>`][-]]
- [[`operator|`][__bitorable`<T, U = T, R = T>`][-]]
- [[`operator^`][__bitxorable`<T, U = T, R = T>`][-]]
- [[`operator<<`][__left_shiftable`<T, U = T, R = T>`][-]]
- [[`operator>>`][__right_shiftable`<T, U = T, R = T>`][-]]
- [[`operator==` and `!=`][__equality_comparable`<T, U = T>`][`!=` is implemented in terms of `==`]]
- [[`operator<`, `>`, `<=`, and `>=`][__less_than_comparable`<T, U = T>`][All are implemented in terms of `<`]]
- [[`operator+=`][__add_assignable`<T, U = T>`][-]]
- [[`operator-=`][__subtract_assignable`<T, U = T>`][-]]
- [[`operator*=`][__multiply_assignable`<T, U = T>`][-]]
- [[`operator/=`][__divide_assignable`<T, U = T>`][-]]
- [[`operator%=`][__mod_assignable`<T, U = T>`][-]]
- [[`operator&=`][__bitand_assignable`<T, U = T>`][-]]
- [[`operator|=`][__bitor_assignable`<T, U = T>`][-]]
- [[`operator^=`][__bitxor_assignable`<T, U = T>`][-]]
- [[`operator<<=`][__left_shift_assignable`<T, U = T>`][-]]
- [[`operator>>=`][__right_shift_assignable`<T, U = T>`][-]]
- [[`operator<<`][__ostreamable`<Os = std::ostream, T = _self>`][-]]
- [[`operator>>`][__istreamable`<Is = std::istream, T = _self>`][-]]
- ]
- [table:misc Miscellaneous Operators
- [[operator][concept][notes]]
- [[`operator()`][__callable`<Sig, T>`][`Sig` should be a function type. T may be const qualified.]]
- [[`operator[]`][__subscriptable`<R, T, N = std::ptrdiff_t>`][`R` should usually be a reference. `T` can be optionally const qualified.]]
- ]
- [table:iterator Iterator Concepts
- [[concept][notes]]
- [[__iterator`<Traversal, T, Reference, Difference>`][Use __same_type to control the iterator's value type.]]
- [[__forward_iterator`<T, Reference, Difference>`][-]]
- [[__bidirectional_iterator`<T, Reference, Difference>`][-]]
- [[__random_access_iterator`<T, Reference, Difference>`][-]]
- ]
- [table:special Special Concepts
- [[concept][notes]]
- [[__same_type`<T>`][Indicates that two types are the same.]]
- ]
- [endsect]
- [xinclude reference.xml]
- [section:rationale Rationale]
- [section Why do I have to specify the presence of a destructor explicitly?]
- When using references the destructor isn't needed.
- By not assuming it implicitly, we allow capturing
- types with private or protected destructors by reference.
- For the sake of consistency, it must be specified
- when capturing by value as well.
- [endsect]
- [section Why non-member functions?]
- The members of __any can be customized. By using
- free functions, we guarantee that we don't interfere
- with anything that a user might want.
- [endsect]
- [section:placeholder Why are the placeholders called `_a`, `_b` and not `_1` `_2`]
- An earlier version of the library used the names `_1`, `_2`, etc.
- instead of `_a`, `_b`, etc. This caused a certain amount
- of confusion because the numbered placeholders are
- already used with a somewhat different meaning by several
- other libraries including Boost/Std Bind, Boost.Phoenix,
- and Boost.MPL. I eventually decided that since the
- placeholders represented named parameters instead of positional parameters,
- letters were more appropriate than numbers.
- [endsect]
- [section:ref Why not use `boost::ref` for references?]
- Boost.Function allows you to use `boost::ref` to store
- a reference to a function object. However, in the
- general case treating references and values in the
- same way causes inconsistent behavior that is difficult
- to reason about. If Boost.TypeErasure handled references
- like this, then, when you copy an __any, you would have
- no idea whether the new object is a real copy or
- just a new reference to the same underlying object.
- Boost.Function can get away with it, because it doesn't
- expose any mutating operations on the stored function object.
- Another method that has been proposed is only to
- keep a reference the first time.
- int i = 2;
- any x = ref(i);
- any y = x; // makes a copy
- Unfortunately, this doesn't handle all use cases,
- as there is no reliable way to return such a reference
- from a function. In addition it adds overhead whether
- it's needed or not, as we would have to add a flag
- to any to keep track of whether or not it is storing
- a reference. (The alternate method of storing this
- in the "`clone`" method in the vtable is impossibly complex
- to implement given the decoupled vtables that
- Boost.TypeErasure uses and it still adds overhead.).
- [endsect]
- [endsect]
- [section:future Future Work]
- These are just some ideas. There is absolutely no
- guarantee that any of them will ever be implemented.
- * Use SBO.
- * Allow more control over vtable layout.
- * Attempt to reuse sub-tables in conversions.
- * Allow "dynamic_cast". This requires creating
- a global registry of concept mappings.
- * Optimize the compile-time cost.
- [endsect]
- [section:acknowledgements Acknowledgements]
- The name `any` and an early ancestor of my placeholder
- system were taken from Alexander Nasonov's DynamicAny library.
- Thanks to review manager, Lorenzo Caminiti
- and all who participated in the formal review:
- * Christophe Henry
- * Paul Bristow
- * Karsten Ahnert
- * Pete Bartlett
- * Sebastian Redl
- * Hossein Haeri
- * Trigve Siver
- * Julien Nitard
- * Eric Niebler
- * Fabio Fracassi
- * Joel de Guzman
- * Alec Chapman
- * Larry Evans
- * Vincente J. Botet Escriba
- * Marcus Werle
- * Andrey Semashev
- * Dave Abrahams
- * Thomas Jordan
- [endsect]
- [section:related Related Work]
- There are a number of similar libraries in existence. I'm aware
- of at least three.
- * [@http://www.coderage.com/interfaces/ Boost.Interfaces] by Jonathan Turkanis
- * [@http://stlab.adobe.com/group__poly__related.html Adobe Poly]
- * [@http://cpp-experiment.sourceforge.net/boost/libs/dynamic_any/doc/ Boost.dynamic_any] by Alexander Nasonov
- [endsect]
|