|
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