Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r80622 - in sandbox/type_erasure/libs/type_erasure: doc example
From: steven_at_[hidden]
Date: 2012-09-21 16:50:45


Author: steven_watanabe
Date: 2012-09-21 16:50:44 EDT (Fri, 21 Sep 2012)
New Revision: 80622
URL: http://svn.boost.org/trac/boost/changeset/80622

Log:
Try to improve documentation based on the review comments.
Text files modified:
   sandbox/type_erasure/libs/type_erasure/doc/type_erasure.qbk | 198 ++++++++++++++++++++++++---------------
   sandbox/type_erasure/libs/type_erasure/example/basic.cpp | 69 +++++++++++++
   sandbox/type_erasure/libs/type_erasure/example/custom.cpp | 20 ++-
   sandbox/type_erasure/libs/type_erasure/example/overload.cpp | 11 +
   4 files changed, 203 insertions(+), 95 deletions(-)

Modified: sandbox/type_erasure/libs/type_erasure/doc/type_erasure.qbk
==============================================================================
--- sandbox/type_erasure/libs/type_erasure/doc/type_erasure.qbk (original)
+++ sandbox/type_erasure/libs/type_erasure/doc/type_erasure.qbk 2012-09-21 16:50:44 EDT (Fri, 21 Sep 2012)
@@ -65,31 +65,70 @@
 [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]
 
-C++ provides runtime polymorphism through virtual
-functions. They are a very useful feature, but
-they do have some limitations.
-
-* They are intrusive. In generic programming, we can
- design an interface which allows third-party types
- to be adapted to it.
-* They require dynamic memory management. Of course,
- most of the problems can be avoided by using an
- appropriate smart pointer type. Even so, it still
- acts like a pointer rather than a value.
-* Virtual functions' ability to apply multiple
- independent concepts to a single object is limited.
-
-The Boost.TypeErasure library solves these problems
-allowing us to mirror static generic programming
-at runtime.
+The TypeErasure library provides runtime polymorphism
+in C++, superior to that provided by the core language.
 
-[note TypeErasure is not an official Boost library.]
-
-[import ../example/intro.cpp]
-[intro]
+We have two distinct kinds of polymorphism built in to C++,
+virtual functions and templates, which each have
+their 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 function automatically make the requirements
+ on the aruments 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 provides another set
+of trade-offs. As with virtual functions, dispatching
+occurs at runtime and you can define a function once
+in a source file. The requirements are stated up front
+in the form of a Concept. Like templates, the library
+supports value semantics, non-intrusive adaptation, and
+requirements across multiple types.
+
+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]
 
@@ -104,20 +143,34 @@
 [endsect]
 
 [section:basic Basic Usage]
+
 [import ../example/basic.cpp]
 [basic]
-[endsect]
 
-[section:multi Functions with Multiple Arguments]
-[import ../example/multi.cpp]
-[multi]
+[section Composing Concepts]
+[import ../example/compose.cpp]
+[compose]
 [endsect]
 
-[section:convert Conversions]
+[section Conversions]
 [import ../example/convert.cpp]
 [convert]
 [endsect]
 
+[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:references Using References]
 [import ../example/references.cpp]
 [references]
@@ -128,16 +181,9 @@
 [construction]
 [endsect]
 
-[section:concept Concepts in Depth]
-
-[section:custom Defining Custom Concepts]
-[import ../example/custom.cpp]
-[custom]
-[endsect]
-
-[section:compose Composing Concepts]
-[import ../example/compose.cpp]
-[compose]
+[section:multi Functions with Multiple Arguments]
+[import ../example/multi.cpp]
+[multi]
 [endsect]
 
 [section:concept_map Concept Maps]
@@ -145,11 +191,6 @@
 [concept_map]
 [endsect]
 
-[section:overload Overloading]
-[import ../example/overload.cpp]
-[overload]
-[endsect]
-
 [section:overload Associated Types]
 [import ../example/associated.cpp]
 [associated]
@@ -217,29 +258,6 @@
 
 [endsect]
 
-[section:reserved Reserved Identifiers]
-
-The library reserves all names begining with
-`_boost_type_erasure` for use as members. No
-class shall contain such a member except
-those defined by the library.
-
-The library reserves all identifiers begining
-with `BOOST_TYPE_ERASURE` for any use.
-
-FIXME: this is too broad.
-The library reserves all identifiers that
-are either a single upper case letter,
-a single upper case letter followed by
-a sequence of digits, in CamelCase, or
-underscore_separated for use in namespace
-`boost::type_erasure`. Such identifiers may
-not be defined as macros. (Macros defined
-in system headers that I know about are
-excepted for the sake of pragmatism.).
-
-[endsect]
-
 [section:predef Predefined Concepts]
 
 In the following tables, `T` and `U` are the types that the operation
@@ -332,6 +350,19 @@
 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]
+
 [endsect]
 
 [section:design Design Notes]
@@ -515,19 +546,6 @@
 
 [endsect]
 
-[section:placeholder Placeholder Names]
-
-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 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]
-
 [endsect]
 
 [section:feedback Feedback Wanted]
@@ -594,7 +612,29 @@
 
 [section:acknowledgements Acknowledgements]
 
-* The name `any` was taken from Alexander Nasonov's
- DynamicAny library.
+The name `any` was 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]

Modified: sandbox/type_erasure/libs/type_erasure/example/basic.cpp
==============================================================================
--- sandbox/type_erasure/libs/type_erasure/example/basic.cpp (original)
+++ sandbox/type_erasure/libs/type_erasure/example/basic.cpp 2012-09-21 16:50:44 EDT (Fri, 21 Sep 2012)
@@ -22,11 +22,11 @@
     //[basic1
     /*`
         The main class in the library is __any. We can just pass
- it an MPL sequence containing all the concepts that we
- wish to use.
+ it an MPL sequence specifying all the requirements on
+ the types that it can hold.
 
         [note The MPL sequence combines multiple concepts.
- In the rare case when we only want one concept, it doesn't
+ In the rare case when we only want a single concept, it doesn't
         need to be wrapped in an MPL sequence.]
     */
     any<mpl::vector<copy_constructible<>, typeid_<> > > x(10);
@@ -44,7 +44,8 @@
     /*`
         Now, this example doesn't do very much. `x` is approximately
         equivalent to a [@boost:/libs/any/index.html boost::any].
- Let's add a few more features.
+ We can make it more interesting by adding some operators,
+ such as `operator++` and `operator<<`
     */
     any<
         mpl::vector<
@@ -59,9 +60,69 @@
     //]
 }
 
+//[basic3
+/*`
+ The library provides a full set of operators, but this
+ obviously won't cover all use cases; we often need to
+ define our own requirements. Let's take the `push_back`
+ method, defined by several STL containers.
+*/
+
+BOOST_TYPE_ERASURE_MEMBER((has_push_back), push_back, 1)
+
+void append_many(any<has_push_back<void(int)>, _self&> container) {
+ for(int i = 0; i < 10; ++i)
+ container.push_back(i);
+}
+
+/*`
+ There are a few things to note about this. First,
+ we use the macro __BOOST_TYPE_ERASURE_MEMBER to
+ define a concept called `has_push_back` for a
+ member function called `push_back` which takes
+ one argument. When we use `has_push_back`, we have to
+ give it the signature of the function, `void(int)`.
+ This means that we expect to find a function
+ that looks like:
+
+ ``
+ void push_back(int);
+ ``
+
+ Thus, we could call `append_many` with `std::vector<int>`,
+ `std::list<int>`, or `std::vector<long>` (because `int` is
+ convertible to `long`), but not `std::list<std::string>`
+ or `std::set<int>`.
+
+ Also, note the use of `_self&` as the second argument of
+ __any. `_self` is a __placeholder. By using it here,
+ we indicate that the __any stores a reference
+ to another object instead of owning its own object.
+*/
+
+/*`
+ For free functions, we can use __BOOST_TYPE_ERASURE_FREE.
+*/
+
+BOOST_TYPE_ERASURE_FREE((has_swap), swap, 2);
+template<class T = _self>
+struct swappable : mpl::vector<has_swap<void(T&, T&)> > {};
+
+/*`
+ We use the __placeholder `_self` here to indicate which arguments
+ of `swap` should be any's. When we use swap, we want it
+ to look like `has_swap<void(_self&, _self&)>`, since `swap`
+ takes two arguments of the same type by reference. Since
+ the signature of swap always looks like this, we define
+ `swappable<>` as a convenient short-cut.
+*/
+
+//]
+
 //[basic
 //` (For the source of the examples in this section see
 //` [@boost:/libs/type_erasure/example/basic.cpp basic.cpp])
 //` [basic1]
 //` [basic2]
+//` [basic3]
 //]

Modified: sandbox/type_erasure/libs/type_erasure/example/custom.cpp
==============================================================================
--- sandbox/type_erasure/libs/type_erasure/example/custom.cpp (original)
+++ sandbox/type_erasure/libs/type_erasure/example/custom.cpp 2012-09-21 16:50:44 EDT (Fri, 21 Sep 2012)
@@ -18,14 +18,16 @@
 
 //[custom1
 /*`
- Let's define a concept to allow push_back on a sequence.
- To do this, we create a class template with a template
- parameter for each argument, and a static member function
+ Earlier, we used __BOOST_TYPE_ERASURE_MEMBER to define
+ a concept for containers that support `push_back`. Let's
+ take a look at what this actually entails. The first thing
+ we need is a class template with a template parameter for
+ each argument, and a static member function
     called `apply` that calls `push_back`.
 */
 
 template<class C, class T>
-struct push_back
+struct has_push_back
 {
     static void apply(C& cont, const T& arg) { cont.push_back(arg); }
 };
@@ -48,10 +50,10 @@
 namespace boost {
 namespace type_erasure {
 template<class C, class T, class Base>
-struct concept_interface< ::push_back<C, T>, Base, C> : Base
+struct concept_interface<has_push_back<C, T>, Base, C> : Base
 {
     void push_back(typename rebind_any<Base, const T&>::type arg)
- { call(::push_back<C, T>(), *this, arg); }
+ { call(has_push_back<C, T>(), *this, arg); }
 };
 }
 }
@@ -64,9 +66,9 @@
         __call to dispatch the operation.
     */
     std::vector<int> vec;
- any<push_back<_self, int>, _self&> c(vec);
+ any<has_push_back<_self, int>, _self&> c(vec);
     int i = 10;
- call(push_back<_self, int>(), c, i);
+ call(has_push_back<_self, int>(), c, i);
     // vec is [10].
     //]
 }
@@ -81,7 +83,7 @@
         now becomes
     */
     std::vector<int> vec;
- any<push_back<_self, int>, _self&> c(vec);
+ any<has_push_back<_self, int>, _self&> c(vec);
     c.push_back(10);
     /*`
         which is what we want.

Modified: sandbox/type_erasure/libs/type_erasure/example/overload.cpp
==============================================================================
--- sandbox/type_erasure/libs/type_erasure/example/overload.cpp (original)
+++ sandbox/type_erasure/libs/type_erasure/example/overload.cpp 2012-09-21 16:50:44 EDT (Fri, 21 Sep 2012)
@@ -19,8 +19,10 @@
 
 //[overload1
 /*`
- Sometimes we want to use the same concept several times
- with different parameters. Specializing __concept_interface
+ __concept_interface allows us to inject arbitrary declarations
+ into an __any. This is very flexible, but there are some pitfalls
+ to watch out for. Sometimes we want to use the same concept several
+ times with different parameters. Specializing __concept_interface
     in a way that handles overloads correctly is a bit tricky.
     Given a concept foo, we'd like the following to work:
 
@@ -147,7 +149,10 @@
     __rebind_any, then we could end up violating the one definition
     rule by defining the same function twice. Similarly, we use
     SFINAE in the second specialization to make sure that bar is
- only defined once when both arguments are placeholders.
+ only defined once when both arguments are placeholders. It's
+ possible to merge the two specializations with a bit of metaprogramming,
+ but unless you have a lot of arguments, it's probably not
+ worth while.
     
     At first I tried overloading `bar` at namespace scope. This
     seems like a more obvious solution at first. Don't use it.


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk