From 01d61922bca7a8475fa750ae586b2e440a8d0f77 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 16 Sep 2002 19:25:33 +0000 Subject: [PATCH] Added libs/mpl [SVN r15384] --- doc/article.css | 67 + doc/index.html | 504 +++++ doc/msxsl_build.bat | 11 + doc/paper/article.css | 87 + doc/paper/html/acknowl.html | 59 + doc/paper/html/article.css | 82 + doc/paper/html/codegeneration.html | 124 ++ doc/paper/html/example.html | 325 +++ doc/paper/html/index.html | 181 ++ doc/paper/html/intro.html | 359 ++++ doc/paper/html/lambda.html | 165 ++ doc/paper/html/refs.html | 152 ++ doc/paper/html/usage.html | 920 ++++++++ doc/paper/html/xsltproc_build.bat | 11 + doc/paper/mpl_paper.html | 1957 ++++++++++++++++++ doc/paper/msxsl_build.bat | 11 + doc/paper/src/abstract.sgml | 38 + doc/paper/src/acknowl.sgml | 10 + doc/paper/src/body.sgml | 41 + doc/paper/src/codegeneration.sgml | 96 + doc/paper/src/example.sgml | 294 +++ doc/paper/src/introduction.sgml | 375 ++++ doc/paper/src/lambda.sgml | 142 ++ doc/paper/src/metafunctions.sgml | 282 +++ doc/paper/src/references.sgml | 247 +++ doc/paper/src/sequences.sgml | 566 +++++ doc/paper/src/typeselection.sgml | 242 +++ doc/paper/src/usage.sgml | 8 + doc/ref/Acknowledgements.html | 7 + doc/ref/Algorithms.html | 40 + doc/ref/Bidirectional_Iterator.html | 50 + doc/ref/Bidirectional_Sequence.html | 35 + doc/ref/Categorized_index.html | 84 + doc/ref/Extensible_Sequence.html | 40 + doc/ref/Forward_Iterator.html | 34 + doc/ref/Forward_Sequence.html | 48 + doc/ref/Input_Iterator.html | 44 + doc/ref/Integral_Constant.html | 43 + doc/ref/Iterators.html | 25 + doc/ref/Metafunction.html | 60 + doc/ref/Metafunctions.html | 39 + doc/ref/Random_Access_Iterator.html | 48 + doc/ref/Random_Access_Sequence.html | 35 + doc/ref/Reference/advance.html | 62 + doc/ref/Reference/at.html | 59 + doc/ref/Reference/at_c.html | 59 + doc/ref/Reference/back.html | 64 + doc/ref/Reference/begin.html | 56 + doc/ref/Reference/clear.html | 60 + doc/ref/Reference/contains.html | 58 + doc/ref/Reference/copy.html | 70 + doc/ref/Reference/copy_backward.html | 70 + doc/ref/Reference/copy_backward_if.html | 70 + doc/ref/Reference/copy_if.html | 70 + doc/ref/Reference/count.html | 60 + doc/ref/Reference/count_if.html | 61 + doc/ref/Reference/distance.html | 56 + doc/ref/Reference/divides.html | 64 + doc/ref/Reference/empty.html | 59 + doc/ref/Reference/end.html | 57 + doc/ref/Reference/equal.html | 59 + doc/ref/Reference/equal_to.html | 61 + doc/ref/Reference/erase.html | 65 + doc/ref/Reference/erase_all.html | 62 + doc/ref/Reference/erase_if.html | 62 + doc/ref/Reference/erase_range.html | 63 + doc/ref/Reference/filter_view.html | 62 + doc/ref/Reference/find.html | 58 + doc/ref/Reference/find_if.html | 58 + doc/ref/Reference/fold.html | 65 + doc/ref/Reference/fold_backward.html | 75 + doc/ref/Reference/front.html | 60 + doc/ref/Reference/greater.html | 61 + doc/ref/Reference/greater_equal.html | 61 + doc/ref/Reference/insert.html | 62 + doc/ref/Reference/insert_range.html | 62 + doc/ref/Reference/iter_fold.html | 65 + doc/ref/Reference/iter_fold_backward.html | 71 + doc/ref/Reference/iter_fold_if.html | 70 + doc/ref/Reference/iterator_category.html | 62 + doc/ref/Reference/less.html | 61 + doc/ref/Reference/less_equal.html | 61 + doc/ref/Reference/list.html | 45 + doc/ref/Reference/list_c.html | 58 + doc/ref/Reference/logical_and.html | 62 + doc/ref/Reference/logical_not.html | 51 + doc/ref/Reference/logical_or.html | 62 + doc/ref/Reference/lower_bound.html | 60 + doc/ref/Reference/minus.html | 64 + doc/ref/Reference/modulus.html | 61 + doc/ref/Reference/multiplies.html | 64 + doc/ref/Reference/negate.html | 60 + doc/ref/Reference/next.html | 61 + doc/ref/Reference/not_equal_to.html | 61 + doc/ref/Reference/plus.html | 64 + doc/ref/Reference/pop_back.html | 71 + doc/ref/Reference/pop_front.html | 71 + doc/ref/Reference/prior.html | 61 + doc/ref/Reference/push_back.html | 63 + doc/ref/Reference/push_front.html | 64 + doc/ref/Reference/range_c.html | 71 + doc/ref/Reference/remove.html | 59 + doc/ref/Reference/remove_if.html | 59 + doc/ref/Reference/replace.html | 61 + doc/ref/Reference/replace_if.html | 61 + doc/ref/Reference/reverse.html | 61 + doc/ref/Reference/size.html | 60 + doc/ref/Reference/sort.html | 62 + doc/ref/Reference/transform.html | 59 + doc/ref/Reference/transform_view.html | 61 + doc/ref/Reference/unique.html | 62 + doc/ref/Reference/upper_bound.html | 60 + doc/ref/Reference/vector.html | 77 + doc/ref/Reference/vector_c.html | 58 + doc/ref/Sequence.html | 49 + doc/ref/Sequences.html | 46 + doc/ref/Table_of_Content.html | 14 + doc/ref/Trivial_Iterator.html | 46 + doc/ref/mpl_logo.jpg | Bin 0 -> 1428 bytes doc/ref/mpl_wiki.css | 41 + doc/src/acknw.sgml | 18 + doc/src/apply_if.sgml | 130 ++ doc/src/apply_if2.sgml | 55 + doc/src/articleinfo.sgml | 2 + doc/src/bibliography.sgml | 69 + doc/src/body.sgml | 37 + doc/src/howtos.sgml | 58 + doc/src/if.sgml | 66 + doc/src/lambda.sgml | 30 + doc/src/metafunctions.sgml | 37 + doc/src/preface.sgml | 49 + doc/src/sequences.sgml | 30 + doc/src/technical.sgml | 52 + doc/src/tutorial.sgml | 29 + preprocessed/pp.py | 202 ++ preprocessed/src/advance_backward.cpp | 2 + preprocessed/src/advance_forward.cpp | 2 + preprocessed/src/apply.cpp | 2 + preprocessed/src/arg.cpp | 2 + preprocessed/src/basic_bind.cpp | 3 + preprocessed/src/bind.cpp | 2 + preprocessed/src/fold_backward_impl.cpp | 2 + preprocessed/src/fold_impl.cpp | 2 + preprocessed/src/full_lambda.cpp | 3 + preprocessed/src/iter_fold_backward_impl.cpp | 2 + preprocessed/src/iter_fold_if_impl.cpp | 2 + preprocessed/src/iter_fold_impl.cpp | 2 + preprocessed/src/lambda_helper.cpp | 2 + preprocessed/src/lambda_no_ctps.cpp | 2 + preprocessed/src/list.cpp | 2 + preprocessed/src/list10.cpp | 2 + preprocessed/src/list10_c.cpp | 2 + preprocessed/src/list20.cpp | 2 + preprocessed/src/list20_c.cpp | 2 + preprocessed/src/list30.cpp | 2 + preprocessed/src/list30_c.cpp | 2 + preprocessed/src/list40.cpp | 2 + preprocessed/src/list40_c.cpp | 2 + preprocessed/src/list50.cpp | 2 + preprocessed/src/list50_c.cpp | 2 + preprocessed/src/list_c.cpp | 2 + preprocessed/src/lite_vector10.cpp | 3 + preprocessed/src/lite_vector10_c.cpp | 3 + preprocessed/src/lite_vector20.cpp | 3 + preprocessed/src/lite_vector20_c.cpp | 3 + preprocessed/src/lite_vector30.cpp | 3 + preprocessed/src/lite_vector30_c.cpp | 3 + preprocessed/src/lite_vector40.cpp | 3 + preprocessed/src/lite_vector40_c.cpp | 3 + preprocessed/src/lite_vector50.cpp | 3 + preprocessed/src/lite_vector50_c.cpp | 3 + preprocessed/src/meta_fun.cpp | 2 + preprocessed/src/placeholder.cpp | 2 + preprocessed/src/vector.cpp | 2 + preprocessed/src/vector10.cpp | 2 + preprocessed/src/vector10_c.cpp | 2 + preprocessed/src/vector20.cpp | 2 + preprocessed/src/vector20_c.cpp | 2 + preprocessed/src/vector30.cpp | 2 + preprocessed/src/vector30_c.cpp | 2 + preprocessed/src/vector40.cpp | 2 + preprocessed/src/vector40_c.cpp | 2 + preprocessed/src/vector50.cpp | 2 + preprocessed/src/vector50_c.cpp | 2 + preprocessed/src/vector_c.cpp | 2 + test/Jamfile | 58 + test/advance.cpp | 37 + test/always.cpp | 46 + test/apply.cpp | 115 + test/apply_if.cpp | 57 + test/arithmetic.cpp | 53 + test/assert_is_same.cpp | 32 + test/at.cpp | 39 + test/back.cpp | 35 + test/bind.cpp | 60 + test/bool_c.cpp | 38 + test/comparison.cpp | 53 + test/copy.cpp | 42 + test/copy_backward.cpp | 42 + test/copy_backward_if.cpp | 43 + test/copy_if.cpp | 44 + test/count.cpp | 43 + test/count_if.cpp | 43 + test/distance.cpp | 45 + test/empty.cpp | 32 + test/equal.cpp | 37 + test/erase.cpp | 50 + test/erase_range.cpp | 43 + test/filter_view.cpp | 41 + test/find.cpp | 45 + test/find_if.cpp | 45 + test/for_each.cpp | 59 + test/front.cpp | 44 + test/identity.cpp | 29 + test/if.cpp | 36 + test/insert.cpp | 36 + test/insert_range.cpp | 36 + test/int_c.cpp | 39 + test/integral_c.cpp | 46 + test/lambda.cpp | 77 + test/list.cpp | 29 + test/list_c.cpp | 64 + test/logical.cpp | 47 + test/lower_bound.cpp | 32 + test/meta_fun.cpp | 31 + test/next.cpp | 36 + test/pop_front.cpp | 44 + test/push_front.cpp | 45 + test/range_c.cpp | 51 + test/replace.cpp | 33 + test/replace_if.cpp | 37 + test/reverse.cpp | 36 + test/size.cpp | 32 + test/size_of.cpp | 34 + test/transform.cpp | 35 + test/transform_view.cpp | 35 + test/unique.cpp | 34 + test/upper_bound.cpp | 35 + 238 files changed, 15885 insertions(+) create mode 100644 doc/article.css create mode 100644 doc/index.html create mode 100755 doc/msxsl_build.bat create mode 100644 doc/paper/article.css create mode 100644 doc/paper/html/acknowl.html create mode 100644 doc/paper/html/article.css create mode 100644 doc/paper/html/codegeneration.html create mode 100644 doc/paper/html/example.html create mode 100644 doc/paper/html/index.html create mode 100644 doc/paper/html/intro.html create mode 100644 doc/paper/html/lambda.html create mode 100644 doc/paper/html/refs.html create mode 100644 doc/paper/html/usage.html create mode 100755 doc/paper/html/xsltproc_build.bat create mode 100644 doc/paper/mpl_paper.html create mode 100755 doc/paper/msxsl_build.bat create mode 100644 doc/paper/src/abstract.sgml create mode 100644 doc/paper/src/acknowl.sgml create mode 100644 doc/paper/src/body.sgml create mode 100644 doc/paper/src/codegeneration.sgml create mode 100644 doc/paper/src/example.sgml create mode 100644 doc/paper/src/introduction.sgml create mode 100644 doc/paper/src/lambda.sgml create mode 100644 doc/paper/src/metafunctions.sgml create mode 100644 doc/paper/src/references.sgml create mode 100644 doc/paper/src/sequences.sgml create mode 100644 doc/paper/src/typeselection.sgml create mode 100644 doc/paper/src/usage.sgml create mode 100644 doc/ref/Acknowledgements.html create mode 100644 doc/ref/Algorithms.html create mode 100644 doc/ref/Bidirectional_Iterator.html create mode 100644 doc/ref/Bidirectional_Sequence.html create mode 100644 doc/ref/Categorized_index.html create mode 100644 doc/ref/Extensible_Sequence.html create mode 100644 doc/ref/Forward_Iterator.html create mode 100644 doc/ref/Forward_Sequence.html create mode 100644 doc/ref/Input_Iterator.html create mode 100644 doc/ref/Integral_Constant.html create mode 100644 doc/ref/Iterators.html create mode 100644 doc/ref/Metafunction.html create mode 100644 doc/ref/Metafunctions.html create mode 100644 doc/ref/Random_Access_Iterator.html create mode 100644 doc/ref/Random_Access_Sequence.html create mode 100644 doc/ref/Reference/advance.html create mode 100644 doc/ref/Reference/at.html create mode 100644 doc/ref/Reference/at_c.html create mode 100644 doc/ref/Reference/back.html create mode 100644 doc/ref/Reference/begin.html create mode 100644 doc/ref/Reference/clear.html create mode 100644 doc/ref/Reference/contains.html create mode 100644 doc/ref/Reference/copy.html create mode 100644 doc/ref/Reference/copy_backward.html create mode 100644 doc/ref/Reference/copy_backward_if.html create mode 100644 doc/ref/Reference/copy_if.html create mode 100644 doc/ref/Reference/count.html create mode 100644 doc/ref/Reference/count_if.html create mode 100644 doc/ref/Reference/distance.html create mode 100644 doc/ref/Reference/divides.html create mode 100644 doc/ref/Reference/empty.html create mode 100644 doc/ref/Reference/end.html create mode 100644 doc/ref/Reference/equal.html create mode 100644 doc/ref/Reference/equal_to.html create mode 100644 doc/ref/Reference/erase.html create mode 100644 doc/ref/Reference/erase_all.html create mode 100644 doc/ref/Reference/erase_if.html create mode 100644 doc/ref/Reference/erase_range.html create mode 100644 doc/ref/Reference/filter_view.html create mode 100644 doc/ref/Reference/find.html create mode 100644 doc/ref/Reference/find_if.html create mode 100644 doc/ref/Reference/fold.html create mode 100644 doc/ref/Reference/fold_backward.html create mode 100644 doc/ref/Reference/front.html create mode 100644 doc/ref/Reference/greater.html create mode 100644 doc/ref/Reference/greater_equal.html create mode 100644 doc/ref/Reference/insert.html create mode 100644 doc/ref/Reference/insert_range.html create mode 100644 doc/ref/Reference/iter_fold.html create mode 100644 doc/ref/Reference/iter_fold_backward.html create mode 100644 doc/ref/Reference/iter_fold_if.html create mode 100644 doc/ref/Reference/iterator_category.html create mode 100644 doc/ref/Reference/less.html create mode 100644 doc/ref/Reference/less_equal.html create mode 100644 doc/ref/Reference/list.html create mode 100644 doc/ref/Reference/list_c.html create mode 100644 doc/ref/Reference/logical_and.html create mode 100644 doc/ref/Reference/logical_not.html create mode 100644 doc/ref/Reference/logical_or.html create mode 100644 doc/ref/Reference/lower_bound.html create mode 100644 doc/ref/Reference/minus.html create mode 100644 doc/ref/Reference/modulus.html create mode 100644 doc/ref/Reference/multiplies.html create mode 100644 doc/ref/Reference/negate.html create mode 100644 doc/ref/Reference/next.html create mode 100644 doc/ref/Reference/not_equal_to.html create mode 100644 doc/ref/Reference/plus.html create mode 100644 doc/ref/Reference/pop_back.html create mode 100644 doc/ref/Reference/pop_front.html create mode 100644 doc/ref/Reference/prior.html create mode 100644 doc/ref/Reference/push_back.html create mode 100644 doc/ref/Reference/push_front.html create mode 100644 doc/ref/Reference/range_c.html create mode 100644 doc/ref/Reference/remove.html create mode 100644 doc/ref/Reference/remove_if.html create mode 100644 doc/ref/Reference/replace.html create mode 100644 doc/ref/Reference/replace_if.html create mode 100644 doc/ref/Reference/reverse.html create mode 100644 doc/ref/Reference/size.html create mode 100644 doc/ref/Reference/sort.html create mode 100644 doc/ref/Reference/transform.html create mode 100644 doc/ref/Reference/transform_view.html create mode 100644 doc/ref/Reference/unique.html create mode 100644 doc/ref/Reference/upper_bound.html create mode 100644 doc/ref/Reference/vector.html create mode 100644 doc/ref/Reference/vector_c.html create mode 100644 doc/ref/Sequence.html create mode 100644 doc/ref/Sequences.html create mode 100644 doc/ref/Table_of_Content.html create mode 100644 doc/ref/Trivial_Iterator.html create mode 100644 doc/ref/mpl_logo.jpg create mode 100644 doc/ref/mpl_wiki.css create mode 100644 doc/src/acknw.sgml create mode 100644 doc/src/apply_if.sgml create mode 100644 doc/src/apply_if2.sgml create mode 100644 doc/src/articleinfo.sgml create mode 100644 doc/src/bibliography.sgml create mode 100644 doc/src/body.sgml create mode 100644 doc/src/howtos.sgml create mode 100644 doc/src/if.sgml create mode 100644 doc/src/lambda.sgml create mode 100644 doc/src/metafunctions.sgml create mode 100644 doc/src/preface.sgml create mode 100644 doc/src/sequences.sgml create mode 100644 doc/src/technical.sgml create mode 100644 doc/src/tutorial.sgml create mode 100644 preprocessed/pp.py create mode 100644 preprocessed/src/advance_backward.cpp create mode 100644 preprocessed/src/advance_forward.cpp create mode 100644 preprocessed/src/apply.cpp create mode 100644 preprocessed/src/arg.cpp create mode 100644 preprocessed/src/basic_bind.cpp create mode 100644 preprocessed/src/bind.cpp create mode 100644 preprocessed/src/fold_backward_impl.cpp create mode 100644 preprocessed/src/fold_impl.cpp create mode 100644 preprocessed/src/full_lambda.cpp create mode 100644 preprocessed/src/iter_fold_backward_impl.cpp create mode 100644 preprocessed/src/iter_fold_if_impl.cpp create mode 100644 preprocessed/src/iter_fold_impl.cpp create mode 100644 preprocessed/src/lambda_helper.cpp create mode 100644 preprocessed/src/lambda_no_ctps.cpp create mode 100644 preprocessed/src/list.cpp create mode 100644 preprocessed/src/list10.cpp create mode 100644 preprocessed/src/list10_c.cpp create mode 100644 preprocessed/src/list20.cpp create mode 100644 preprocessed/src/list20_c.cpp create mode 100644 preprocessed/src/list30.cpp create mode 100644 preprocessed/src/list30_c.cpp create mode 100644 preprocessed/src/list40.cpp create mode 100644 preprocessed/src/list40_c.cpp create mode 100644 preprocessed/src/list50.cpp create mode 100644 preprocessed/src/list50_c.cpp create mode 100644 preprocessed/src/list_c.cpp create mode 100644 preprocessed/src/lite_vector10.cpp create mode 100644 preprocessed/src/lite_vector10_c.cpp create mode 100644 preprocessed/src/lite_vector20.cpp create mode 100644 preprocessed/src/lite_vector20_c.cpp create mode 100644 preprocessed/src/lite_vector30.cpp create mode 100644 preprocessed/src/lite_vector30_c.cpp create mode 100644 preprocessed/src/lite_vector40.cpp create mode 100644 preprocessed/src/lite_vector40_c.cpp create mode 100644 preprocessed/src/lite_vector50.cpp create mode 100644 preprocessed/src/lite_vector50_c.cpp create mode 100644 preprocessed/src/meta_fun.cpp create mode 100644 preprocessed/src/placeholder.cpp create mode 100644 preprocessed/src/vector.cpp create mode 100644 preprocessed/src/vector10.cpp create mode 100644 preprocessed/src/vector10_c.cpp create mode 100644 preprocessed/src/vector20.cpp create mode 100644 preprocessed/src/vector20_c.cpp create mode 100644 preprocessed/src/vector30.cpp create mode 100644 preprocessed/src/vector30_c.cpp create mode 100644 preprocessed/src/vector40.cpp create mode 100644 preprocessed/src/vector40_c.cpp create mode 100644 preprocessed/src/vector50.cpp create mode 100644 preprocessed/src/vector50_c.cpp create mode 100644 preprocessed/src/vector_c.cpp create mode 100644 test/Jamfile create mode 100644 test/advance.cpp create mode 100644 test/always.cpp create mode 100644 test/apply.cpp create mode 100644 test/apply_if.cpp create mode 100644 test/arithmetic.cpp create mode 100644 test/assert_is_same.cpp create mode 100644 test/at.cpp create mode 100644 test/back.cpp create mode 100644 test/bind.cpp create mode 100644 test/bool_c.cpp create mode 100644 test/comparison.cpp create mode 100644 test/copy.cpp create mode 100644 test/copy_backward.cpp create mode 100644 test/copy_backward_if.cpp create mode 100644 test/copy_if.cpp create mode 100644 test/count.cpp create mode 100644 test/count_if.cpp create mode 100644 test/distance.cpp create mode 100644 test/empty.cpp create mode 100644 test/equal.cpp create mode 100644 test/erase.cpp create mode 100644 test/erase_range.cpp create mode 100644 test/filter_view.cpp create mode 100644 test/find.cpp create mode 100644 test/find_if.cpp create mode 100644 test/for_each.cpp create mode 100644 test/front.cpp create mode 100644 test/identity.cpp create mode 100644 test/if.cpp create mode 100644 test/insert.cpp create mode 100644 test/insert_range.cpp create mode 100644 test/int_c.cpp create mode 100644 test/integral_c.cpp create mode 100644 test/lambda.cpp create mode 100644 test/list.cpp create mode 100644 test/list_c.cpp create mode 100644 test/logical.cpp create mode 100644 test/lower_bound.cpp create mode 100644 test/meta_fun.cpp create mode 100644 test/next.cpp create mode 100644 test/pop_front.cpp create mode 100644 test/push_front.cpp create mode 100644 test/range_c.cpp create mode 100644 test/replace.cpp create mode 100644 test/replace_if.cpp create mode 100644 test/reverse.cpp create mode 100644 test/size.cpp create mode 100644 test/size_of.cpp create mode 100644 test/transform.cpp create mode 100644 test/transform_view.cpp create mode 100644 test/unique.cpp create mode 100644 test/upper_bound.cpp diff --git a/doc/article.css b/doc/article.css new file mode 100644 index 0000000..7dc14de --- /dev/null +++ b/doc/article.css @@ -0,0 +1,67 @@ +div.articletitle +{ + text-align: center; + text-transform: uppercase; +} + +div.authorgroup +{ + text-align: center; +} + +h3.title span.emphasis em +{ + font-style: normal; + text-decoration: underline; +} + +body +{ + background-color: white; + color: black; +} + +sup +{ + font-size: x-small; + font-weight: lighter; +} + +a:link, +a:visited +{ + color: #505050; +} + + sup a:link +,sup a:visited +,a.interlink:link +,a.interlink:visited +{ + color: #505050; + text-decoration: none; +} + +div.biblioentry p +{ + border-style: none none none solid; + border-width: 1px; + border-color: silver; + margin-top: -1em; + padding-left: 0.5em; + padding-top: 0.25em; +} + +div.footnote p +{ + margin-bottom: -0.5em; +} + +pre.programlisting +{ + + border-style: none none none solid; + border-width: 1px; + border-color: silver; + padding-left: 1em; +} diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..fbf1c0d --- /dev/null +++ b/doc/index.html @@ -0,0 +1,504 @@ + + + + +The Boost MPL Library + + + + +
+
+
+
+

The Boost MPL Library

+
+
+
+ +
+

Table of Contents

+ +
+
1. Preface
+ +
2. Sources
+ +
3. Mini-tutorial
+ +
+
+
3.1. Conventions used
+ +
3.2. Metafunctions
+ +
3.3. Compile-time if
+ +
3.4. apply_if
+ +
3.5. apply_if, part 2
+
+
+ +
4. Technical details
+ +
+
+
4.1. Physical structure
+ +
4.2. Dependencies
+ +
4.3. Portability
+
+
+ +
5. Acknowledgements
+ +
Bibliography
+
+
+ +
+
+
+

1. Preface

+
+
+ +

The MPL library is a C++ template metaprogramming framework of compile-time algorithms, sequences and metafunction classes. The two main documentation sources for the library is “the MPL paper”, and the library's reference documentation. If you haven't heard about the MPL before, we suggest you to start with the paper, and then move on to the reference documentation and the information in this document.

+ + +
+ +
+
+
+

2. Sources

+
+
+ +

The latest library sources are available from:

+ +
+ +
+ +

The library also requires the latest version of Boost Preprocessor library, that can be also obtained from boost CVS or from here - http://www.mywikinet.com/mpl/preprocessor_19_jul_02.zip.

+ +

A full archive that contains the library itself + all its dependencies - and therefore can be installed over a clean Boost 1.28 distribution - is available from here - http://www.mywikinet.com/mpl/mpl_23_jul_02_full.zip.

+
+ +
+
+
+

3. Mini-tutorial

+
+
+ +
+
+
+

3.1. Conventions used

+
+
+ +

The examples used through this tutorial use fully qualified names, e.g. std::vector instead of plain vector. Any unqualified name refers to a local entity defined in the example itself. The names from boost::mpl namespace are referred to using mpl namespace alias (e.g. mpl::apply instead of boost::mpl::apply), as if the following namespace alias definition were in effect:

+ +
+namespace mpl = boost::mpl;
+
+ +

Note that the library offers a special header, boost/mpl/alias.hpp, including which gives you a rough equivalent of the above. Alternatively, you can always spell the namespace alias definition manually in each translation unit as needed (if you choose to use the shorter namespace notation at all).

+
+ +
+
+
+

3.2. Metafunctions

+
+
+ +

In MPL, the metaprogramming equivalent of a function is a class template containing a nested typedef member aptly named “type”:

+ +
+// on the face of it, not very useful
+template< typename T >
+struct identity 
+{
+    typedef T type;
+};
+
+// perhaps more useful
+template< typename T >
+struct result_type 
+{
+    typedef typename T::result_type type;
+};
+
+ +

“Invoking” a metafunction is as simple as instantiating the class template with particular template parameters (metafunction “arguments”) and accessing the result through the nested type member:

+ +
+typedef identity<int>::type t1; // t1 == int
+typedef result_type< std::unary_function<int,bool> >::type t2; // t2 == bool
+
+
+ +
+
+
+

3.3. Compile-time if

+
+
+ +

The most interesting template metaprograms often contain a lot of decision-making code. Some of conditional decisions/behavior can be handled directly by (partial) class template specialization or function overloading [Vel95a], [Ale00], but in general there is a need for a standalone library primitive that would allow one to choose between two types basing on a compile-time expression. In boost::mpl such primitive is called if_:

+ +
+template< typename T >
+struct heap_holder
+{
+ // ... 
+ private:
+    boost::scoped_ptr<T> m_object;
+};
+
+template< typename T >
+struct stack_holder
+{
+ // ... 
+ private:
+    T m_object;
+};
+
+template< typename T >
+struct can_be_on_stack
+    : mpl::bool_c< (sizeof(T) <= sizeof(double)) >
+{
+};
+
+// use 'if_' to choose where to store 'T' member
+template< typename T >
+struct lightweight
+   : private mpl::if_<
+          can_be_on_stack<T>
+        , stack_holder<T>
+        , heap_holder<T>
+        >::type
+{
+   // ...
+};
+
+ +

Note that the first template parameter of the if_ template is a type that should be a model of Integral Constant concept. The library also provides a less generic but sometimes more convenient form that accepts a condition in form of non-type bool template parameter:

+ +
+template< typename T >
+struct lightweight
+   : private mpl::if_c<
+          (sizeof(T) <= sizeof(double))
+        , stack_holder<T>
+        , heap_holder<T>
+        >::type
+{
+   // ...
+};
+
+
+ +
+
+
+

3.4. apply_if

+
+
+ +

In run-time C++, it is guaranteed that when we reach an if statement, only one branch will be executed. Executing the branch for which the result is not required would be unnecessary and inefficient. More importantly, frequently the non-required branch is invalid, and executing it would cause an error. For instance, the following code would be badly broken if both branches of the statement were evaluated:

+ +
+void fun(giraffe* g)
+{
+    if (g)
+        cout << g->name();
+    else
+        cout << "no giraffe";
+}
+
+ +

In compile-time world, things are different. Which parameters to if_ template are instantiated is determined by the form of each template parameter and the corresponding language rules ([ISO98], section 14.7.1), not by the value of the compile-time expression being switched on. That means that if, in attempt to process a particular if_ construct, the compiler determines that one of its “branch” template parameters is ill-formed, it will issue a diagnostics even if the value of compile-time expression would lead to “choosing” the other, valid parameter type.

+ +

To clarify what we just said, here is a broken first attempt at writing a pointed_type metafunction, that when instantiated for a T that is either a plain pointer or a smart pointer, “returns” the pointed type:

+ +
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , typename boost::remove_pointer<T>::type
+        , typename T::element_type // #1
+        >::type type;
+};
+
+typedef pointed_type< std::auto_ptr<int> >::type int_ptr; // ok
+typedef pointed_type<char*>::type char_ptr; // error in line #1!
+
+ +

If we try to compile the above, we will get something like this:

+ +
+Error: name followed by "::" must be a class or namespace name
+
+ +

because the expression typename T::element_type is not valid in case of T == char*.

+ +

Here's what we need to do to make pointed_type work for plain pointers: 1 instead of instantiating our two potential results before passing them to if_, we need to write metafunctions that can be used to instantiate the results; then we can use if_ to choose a metafunction, and only then should we use that function to get the result.

+ +

boost::remove_pointer already is a metafunction. We just need to write an auxiliary function to return the element_type of a pointer type:

+ +
+namespace aux {
+template< typename T >
+struct element_type
+{
+     typedef typename T::element_type type;
+};
+}
+
+ +

Now we can select the metafunction to call based on the result of boost::is_pointer, and then apply it to form the result:

+ +
+template< typename T >
+struct pointed_type
+{
+ private:
+    // pick a metafunction
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type func_; // #1
+
+ public:
+    // apply the metafunction
+    typedef typename func_::type type;
+};
+
+ +

The key knowledge that makes the above viable is that in line #1 the compiler is guaranteed not to instantiate boost::remove_pointer<T> and aux::element_type<T> templates, - even although they are passed as actual arguments to the if_.

+ +

The described technique is so common in template metaprograms, that it makes sense to facilitate the selection of the nested type member by introducing a high level equivalent to if_ that will do func_::type operation as a part of its invocation. The MPL provides such a template - it's called apply_if. Using it, we can re-write the above code as simply as:

+ +
+[
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::apply_if<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type type;
+};
+
+
+ +
+
+
+

3.5. apply_if, part 2

+
+
+ +

Besides solving the “making the code compile” problem, the apply_if technique we've just learned can be also used to improve metaprogram efficiency.

+ +

Suppose we want to define a high-level wrapper around boost::remove_pointer traits template, which will strip the pointer qualification conditionally. We will call it remove_pointer_if:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::if_<
+          Condition
+        , typename boost::remove_pointer<T>::type
+        , T
+        >::type type;
+};
+
+ +

The above works the first time, but it's not the most optimal implementation. Similar to our previous examples, boost::remove_pointer<T> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource [Abr01], and it is wasted by unnecessary template instantiations.

+ +

Let's see what we need to substitute if_ by apply_if here. We already have one metafunction to pass to apply_if - boost::remove_pointer<T>, but we need a second one, - let's call it f, - such as f<T>::type == T. We could write this one ourselves, but fortunately MPL already provides us with a template that matches this exact definition - it's called identity. Applying this knowledge, we get:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::apply_if<
+          Condition
+        , boost::remove_pointer<T>
+        , mpl::identity<T>
+        >::type type;
+};
+
+
+
+ +
+
+
+

4. Technical details

+
+
+ +
+
+
+

4.1. Physical structure

+
+
+ +

The library provides you with a fine-grained header structure with one header per public component (class/function template), with the header named after the component; for example, boost::mpl::apply<> template is defined in the header boost/mpl/apply.hpp. This scheme both ensures that you don't pay for what you don't use in terms of compilation time/header dependencies, and frees you from memorizing/looking up header/component correspondence. Several composite headers for the entities that are likely to be used together (e.g. logical operations - logical_or, logical_and, etc.) are also provided. It allows one to avoid the burden of spelling many #include directives in programs that make an intensive use of the library facilities. 2

+
+ +
+
+
+

4.2. Dependencies

+
+
+ +

Besides boost/config.hpp header, the MPL heavily depends on two other Boost libraries - the Boost Preprocessor library [PRE], and the Type Traits library [TTL]. These dependencies are essential and cannot be eliminated. In addition to those, the boost/mpl/assert_is_same.hpp header depends on Boost Static Assert library [SAL]. The library tests and examples may depend on some additional Boost libraries, e.g. Boost Bind [BBL]; you don't have to have those unless you are interested in actually compiling the tests/examples (probably you are, though).

+
+ +
+
+
+

4.3. Portability

+
+
+ +

Below is the list of compilers the library has been tested with:

+ +
+
    +
  • Microsoft Visual C++ 6.0, SP 5
  • + +
  • Microsoft Visual C++ .NET (7.0)
  • + +
  • Metrowerks CodeWariror 7.2/8.1
  • + +
  • Intel C++ Compiler 5.0, 6.0
  • + +
  • GCC 2.95.3-5
  • + +
  • GCC 3.1
  • + +
  • Comeau C/C++ 4.2.45/4.3.0
  • + +
  • Borland C++ 5.5.1
  • +
+
+ +

An incomplete matrix of recent test compilation results is available from here - http://www.mywikinet.com/mpl/log.html.

+
+
+ +
+
+
+

5. Acknowledgements

+
+
+ +

Following is a list of people who in one or another way contributed to the library development. The list is work in progress!

+ +

David Abrahams, Emily Winch, Eric Friedman, Vesa Karvonen, Peter Dimov, Mat Marcus, Fernando Cacciola, Paul Mensonides, David B. Held, John Bandela, Arnaldur Gylfason, Hamish Mackenzie.

+ +

Copyright on this document. Copyright © 2002 Aleksey Gurtovoy, David Abrahams and Emily Winch.

+
+ +
+
+
+

Bibliography

+
+
+ +
+

[Abr01] David Abrahams and Carlos Pinto Coelho, Effects of Metaprogramming Style on Compilation Time, 2001

+
+ +
+

[Ale00] Andrei Alexandrescu, On Conversions between Types and Values, C/C++ Users Journal, October 2000

+
+ +
+

[BBL] Boost Bind library, http://www.boost.org/libs/bind/bind.html

+
+ +
+

[ISO98] ISO/IEC 14882:1998(E), Programming languages — C++, ISO/IEC, 1998

+
+ +
+

[PRE] Vesa Karvonen, Boost Preprocessor Metaprogramming library, http://www.boost.org/libs/preprocessor/doc/

+
+ +
+

[TTL] Boost Type Traits library, http://www.boost.org/libs/type_traits/

+
+ +
+

[SAL] Boost Static Assert library, http://www.boost.org/libs/static_assert/static_assert.htm

+
+ +
+

[Vel95a] Todd Veldhuizen, Using C++ template metaprograms, C++ Report, SIGS Publications Inc., ISSN 1040-6042, Vol. 7, No. 4, pp. 36-43, May 1995

+
+
+ +

+
+
+

1 It would be easy to implement pointed_type using partial specialization to distinguish the case where T is a pointer. if_ is used here to avoid creating a complicated example.

+
+ +
+

2 The Boost Preprocessor library [PRE] exposes a very similar physical organization; in fact, the libraries even share the common subdirectory naming (mpl/arithmetic <-> preprocessor/arithmetic, mpl/comparison <-> preprocessor/comparison, etc.).

+
+
+
+ + + diff --git a/doc/msxsl_build.bat b/doc/msxsl_build.bat new file mode 100755 index 0000000..ca82add --- /dev/null +++ b/doc/msxsl_build.bat @@ -0,0 +1,11 @@ +@echo off + +if "%4" == "" goto build +f:\msxsl\msxsl.exe f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\titlepage.templates.xml f:\home\depot\xml\stylesheets\docbook-xsl-1.52.2\template\titlepage.xsl | f:\msxsl\msxsl.exe - f:\msxsl\to_utf8.xsl -o f:\home\depot\xml\stylesheets\docbook-1.50.0\html\titlepage.templates.xsl + +:build +sx -x lower -x empty %2 >%3.xml +f:\msxsl\msxsl.exe %3.xml f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\my\%1 -o %3 +del %3.xml +f:\tidy\tidy.exe -config f:\tidy\config.txt -m %3 +f:\tidy\tidy_attr.py %3 diff --git a/doc/paper/article.css b/doc/paper/article.css new file mode 100644 index 0000000..dc41d0b --- /dev/null +++ b/doc/paper/article.css @@ -0,0 +1,87 @@ +div.articletitle +{ + text-align: center; + text-transform: uppercase; +} + +div.authorgroup +{ + text-align: center; +} + +h3.title span.emphasis em +{ + font-style: normal; + text-decoration: underline; +} + +body +{ + background-color: white; + color: black; +} + +sup +{ + font-size: x-small; + font-weight: lighter; +} + +a:link +,a:visited +{ + color: #505050; +} + + sup a:link +,sup a:visited +,a.interlink:link +,a.interlink:visited +{ + color: #505050; + text-decoration: none; +} + +div.biblioentry p +{ + border-style: none none none solid; + border-width: 1px; + border-color: silver; + margin-top: -1em; + padding-left: 0.5em; + padding-top: 0.25em; +} + +div.footnote p +{ + margin-bottom: -0.5em; +} + +div.table table +{ + border: solid; + border-width: 1px; + border-color: silver; +} + +div.table table tr th +{ + background-color: #f0f0f0; + padding-left: 1em; + padding-right: 1em; +} + +div.table table tr td +{ + padding-left: 1em; + padding-right: 1em; +} + +pre.programlisting +{ + + border-style: none none none solid; + border-width: 1px; + border-color: silver; + padding-left: 1em; +} diff --git a/doc/paper/html/acknowl.html b/doc/paper/html/acknowl.html new file mode 100644 index 0000000..16f7a65 --- /dev/null +++ b/doc/paper/html/acknowl.html @@ -0,0 +1,59 @@ + + + + +6. Acknowledgements + + + + + + + + + + + +
+
+
+

6. Acknowledgements

+
+
+ +

Peter Dimov contributed the bind functionality without which compile-time lambda expressions wouldn't have been possible. The MPL implementation would have been much more difficult without Vesa Karvonen's wonderful Boost Preprocessor Metaprogramming Library. Authors are also greatly indebted to David B. Held who kindly volunteered to thoroughly edit this document. Of course, any remaining errors are exclusively ours.

+
+ + + + + diff --git a/doc/paper/html/article.css b/doc/paper/html/article.css new file mode 100644 index 0000000..7c183ea --- /dev/null +++ b/doc/paper/html/article.css @@ -0,0 +1,82 @@ +div.articletitle +{ + text-align: center; + text-transform: uppercase; +} + +div.authorgroup +{ + text-align: center; +} + +h3.title span.emphasis em +{ + font-style: normal; + text-decoration: underline; +} + +body +{ + background-color: white; + color: black; +} + +sup +{ + font-size: x-small; + font-weight: lighter; +} + +a:link +,a:visited +{ + color: #505050; +} + + sup a:link +,sup a:visited +,a.interlink:link +,a.interlink:visited +{ + color: #505050; + text-decoration: none; +} + +div.biblioentry p +{ + border-style: none none none solid; + border-width: 1px; + border-color: silver; + margin-top: -1em; + padding-left: 0.5em; + padding-top: 0.25em; +} + +div.table table +{ + border: solid; + border-width: 1px; + border-color: silver; +} + +div.table table tr th +{ + background-color: #f0f0f0; + padding-left: 1em; + padding-right: 1em; +} + +div.table table tr td +{ + padding-left: 1em; + padding-right: 1em; +} + +pre.programlisting +{ + + border-style: none none none solid; + border-width: 1px; + border-color: silver; + padding-left: 1em; +} diff --git a/doc/paper/html/codegeneration.html b/doc/paper/html/codegeneration.html new file mode 100644 index 0000000..ca0e68f --- /dev/null +++ b/doc/paper/html/codegeneration.html @@ -0,0 +1,124 @@ + + + + +4. Code generation facilities + + + + + + + + + + + +
+
+
+

4. Code generation facilities

+
+
+ +

There are cases, especially in the domain of numeric computation, when one wants to perform some part of the calculations at compile-time, and then pass the results to a run-time part of the program for further processing. For example, suppose one has implemented a complex compile-time algorithm that works with fixed-point arithmetic:

+ +
+// fixed-point algorithm input
+typedef mpl::vector<
+      mpl::fixed_c<-1,2345678>
+    , mpl::fixed_c<9,0001>
+    // ..
+    , mpl::fixed_c<3,14159>
+    > input_data;
+
+/*
+  complex compile-time algorithm 
+*/
+typedef /*...*/ result_data;
+
+ +

Suppose the result_data here is a sequence of mpl::fixed_c types that keeps the results of the algorithm, and now one wishes to feed that result to the run-time part of the algorithm. With MPL she can do this:

+ +
+double my_algorithm()
+{
+    // passing the results to the run-time part of the program
+    std::vector<double> results;
+    results.reserve(mpl::size<result_data>::value);
+    mpl::for_each<numbers,_>(
+          boost::bind(&std::vector<double>::push_back, &results, _1)
+        );
+    // ...
+}
+
+ +

The for_each<numbers,_>(...) call is what actually transfers the compile-time result_data into run-time results. for_each is a function template declared as:

+ +
+template<
+      typename Seq
+    , typename TransformOp
+    , typename F
+    >
+void for_each(F f)
+{
+    // ...
+}
+
+ +

To call the function, one is required to explicitly provide two actual template parameters, a compile-time sequence Seq and a unary transformation metafunction TransformOp, plus a run-time function argument f (in our example, numbers, _, and boost::bind(...) correspondingly). f is a function object which operator() is called for every element in the Seq tranfromed by TransformOp.

+ +

Applying this to our example, the

+ +
+mpl::for_each<numbers,_>(
+      boost::bind(&std::vector<double>::push_back, &results, _1)
+    );
+
+ +

call is roughly equivalent to this:

+ +
+f(mpl::apply< _,mpl::at_c<result_data,0>::type >::type());
+f(mpl::apply< _,mpl::at_c<result_data,1>::type >::type());
+// ...
+f(mpl::apply< _,mpl::at_c<result_data,n>::type >::type());
+
+ +

where n == mpl::size<result_data>::type::value.

+
+ + + + + diff --git a/doc/paper/html/example.html b/doc/paper/html/example.html new file mode 100644 index 0000000..356fe10 --- /dev/null +++ b/doc/paper/html/example.html @@ -0,0 +1,325 @@ + + + + +5. Example: a compile-time FSM generator + + + + + + + + + + + +
+
+
+

5. Example: a compile-time FSM generator

+
+
+ +

Finite state machines (FSMs) are an important tool for describing and implementing program behavior [HU79], [Mar98]. They also are a good example of a domain in which metaprogramming can be applied to reduce the amount of repetitive and boilerplate operations one must perform in order to implement these simple mathematical models in code. Below we present a simple state machine generator that has been implemented using Boost Metaprogramming Library facilities. The generator takes a compile-time automata description, and converts it into C++ code that implements the FSM at run-time.

+ +

The FSM description is basically a combination of states and events plus a state transition table (STT), which ties them all together. The generator walks through the table and generates the state machine's process_event method that is the essence of an FSM.

+ +

Suppose we want to implement a simple music player using a finite state machine model. The state transition table for the FSM is shown in Table 1. The STT format reflects the way one usually describes the behavior of an FSM in plain English. For example, the first line of the table can be read as follows: ‘If the model is in the stopped state and the play_event is received, then the do_play transition function is called, and the model transitions to the playing state’.

+ +
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StateEventNext stateTransition function
stoppedplay_eventplayingdo_play
playingstop_eventstoppeddo_stop
playingpause_eventpauseddo_pause
pausedplay_eventplayingdo_resume
pausedstop_eventstoppeddo_stop
+ +

Table 1. Player's state transition table with actions

+
+ +

The transition table provides us with a complete formal definition of the target FSM, and there are several ways to transform that definition into code. For instance, if we define states as members of an enumeration type, and events as classes derived from some base event class 10 , like so:

+ +
+class player
+{
+ public:
+    // event declarations
+    struct event;
+    struct play_event;
+    struct stop_event;
+    struct pause_event;
+
+    // "input" function
+    void process_event(event const&); // throws
+
+ private:
+    // states
+    enum state_t { stopped, playing, paused };
+
+    // transition functions
+    void do_play(play_event const&);
+    void do_stop(stop_event const&);
+    void do_pause(pause_event const&);
+    void do_resume(play_event const&);
+
+ private:
+    state_t m_state;
+};
+
+ +

then the most straightforward way to derive the FSM implementation from the above table would be something like this:

+ +
+void player::process_event(event const& e)
+{
+    if (m_state == stopped)
+    {
+        if (typeid(e) == typeid(play_event))
+        {
+            do_play(static_cast<play_event const&>(e));
+            m_state = playing;
+            return;
+        }
+    }
+    else if (m_state == playing)
+    {
+        if (typeid(e) == typeid(stop_event))
+        {
+            do_stop(static_cast<stop_event const&>(e));
+            m_state = stopped;
+            return;
+        }
+
+        if (typeid(e) == typeid(pause_event))
+        {
+            do_pause(static_cast<pause_event const&>(e));
+            m_state = paused;
+            return;
+        }
+    }
+    else if (m_state == paused)
+    {
+        if (typeid(e) == typeid(stop_event))
+        {
+            do_stop(static_cast<stop_event const&>(e));
+            m_state = stopped;
+            return;
+        }
+
+        if (typeid(e) == typeid(play_event))
+        {
+            do_play(static_cast<play_event const&>(e));
+            m_state = playing;
+            return;
+        }
+    }
+    else
+    {
+        throw logic_error(
+            boost::format("unknown state: %d")
+                % static_cast<int>(m_state)
+            );
+    }
+
+    throw std::logic_error(
+        "unexpected event: " + typeid(e).name()
+        );
+}
+
+ +

Although there is nothing particularly wrong with implementing an FSM's structure using nested if (or switch-case) statements, the obvious weakness of this approach is that most of the above code is boilerplate. What one tends to do with boilerplate code is to copy and paste it, then change names etc. to adjust it to its new location; and that's where the errors are most likely to creep in. Since all the lines of event processing look alike (structurally), it's very easy to overlook or forget something that needs to be changed, and many such errors won't appear until the runtime.

+ +

The transition table of our FSM is just five lines long; ideally, we would like the skeleton implementation of the automata's controlling logic to be equally short (or, at least, to look equally short, i.e. to be encapsulated in some form so we never worry about it).

+ +
+
+
+

5.1. Implementation

+
+
+ +

To represent the STT in a C++ program, we define a transition class template that represents a single line of the table. Then the table itself can be represented as a sequence of such lines:

+ +
+typedef mpl::list<
+      transition<stopped, play_event,  playing, &player::do_play>
+    , transition<playing, stop_event,  stopped, &player::do_stop>
+    , transition<playing, pause_event, paused,  &player::do_pause>
+    , transition<paused,  play_event,  playing, &player::do_resume>
+    , transition<paused,  stop_event,  stopped, &player::do_stop>
+    >::type transition_table;
+
+ +

Now, the complete FSM will look like this:

+ +
+class player
+    : state_machine<player>
+{
+ private:
+    typedef player self_t;
+
+    // state invariants
+    void stopped_state_invariant();
+    void playing_state_invariant();
+    void paused_state_invariant();
+
+    // states (invariants are passed as non-type template arguments,
+    // and are called then the FSM enters the corresponding state)
+    typedef state<0, &self_t::stopped_state_invariant> stopped;
+    typedef state<1, &self_t::playing_state_invariant> playing;
+    typedef state<2, &self_t::paused_state_invariant> paused;
+
+ private:
+    // event declarations; events are represented as types, 
+    // and can carry a specific data for each event;
+    // but it's not needed for generator, so we define them later
+    struct play_event;
+    struct stop_event;
+    struct pause_event;
+
+    // transition functions
+    void do_play(play_event const&);
+    void do_stop(stop_event const&);
+    void do_pause(pause_event const&);
+    void do_resume(play_event const&);
+
+    // STT
+    friend class state_machine<player>;
+    typedef mpl::list<
+          transition<stopped, play_event,  playing, &player::do_play>
+        , transition<playing, stop_event,  stopped, &player::do_stop>
+        , transition<playing, pause_event, paused,  &player::do_pause>
+        , transition<paused,  play_event,  playing, &player::do_resume>
+        , transition<paused,  stop_event,  stopped, &player::do_stop>
+        >::type transition_table;
+};
+
+ +

That's all - the above will generate a complete FSM implementation according to our specification. The only thing we need before using it is the definition of the event types (that were just forward declared before):

+ +
+// event definitions
+struct player::play_event
+    : player::event
+{
+};
+
+// ...
+
+ +

The usage is simple as well:

+ +
+int main()
+{
+    // usage example
+    player p;
+    p.process_event(player::play_event());
+    p.process_event(player::pause_event());
+    p.process_event(player::play_event());
+    p.process_event(player::stop_event());
+    return 0;
+}
+
+
+ +
+
+
+

5.2. Related work

+
+
+ +

A notable prior work in the field of automation of general-purpose state machine implementation in C++ is the Robert Martin's State Machine Compiler [SMC]. The SMC takes an ASCII description of the machine's state transition table and produces C++ code that implements the FSM using a variation of State design pattern [Hun91], [GHJ+95]. Lafreniere [Laf00] presents another approach, where no external tools are used, and the FSMs are table driven.

+
+ +

+
+
+

10The events need to be passed to action functions, as they may contain some event-specific information for an action.

+
+
+
+ + + + + diff --git a/doc/paper/html/index.html b/doc/paper/html/index.html new file mode 100644 index 0000000..0ba8e90 --- /dev/null +++ b/doc/paper/html/index.html @@ -0,0 +1,181 @@ + + + + +The Boost C++ Metaprogramming Library + + + + + + + + + +
+
+
+
+

The Boost C++ Metaprogramming Library

+
+
+ +
+
+

Aleksey Gurtovoyi and David Abrahamsii

+ +
iMetaCommunications, agurtovoy@meta-comm.com
+ +
iiBoost Consulting, david.abrahams@rcn.com
+
+
+ +
+
+

Abstract

+ +

This paper describes the Boost C++ template metaprogramming library (MPL), an extensible compile-time framework of algorithms, sequences and metafunction classes. The library brings together important abstractions from the generic and functional programming worlds to build a powerful and easy-to-use toolset which makes template metaprogramming practical enough for the real-world environments. The MPL is heavily influenced by its run-time equivalent - the Standard Template Library (STL), a part of the C++ standard library [STL94], [ISO98]. Like the STL, it defines an open conceptual and implementation framework which can serve as a foundation for future contributions in the domain. The library's fundamental concepts and idioms enable the user to focus on solutions without navigating the universe of possible ad-hoc approaches to a given metaprogramming problem, even if no actual MPL code is used. The library also provides a compile-time lambda expression facility enabling arbitrary currying and composition of class templates, a feature whose runtime counterpart is often cited as missing from the STL. This paper explains the motivation, usage, design, and implementation of the MPL with examples of its real-life applications, and offers some lessons learned about C++ template metaprogramming.

+
+
+ +
+
+

Keywords: template metaprogramming, generic programming, programming languages, C++, STL, type systems, polymorphism, compile-time

+
+
+
+ + +
+ + + + + diff --git a/doc/paper/html/intro.html b/doc/paper/html/intro.html new file mode 100644 index 0000000..1ad5c03 --- /dev/null +++ b/doc/paper/html/intro.html @@ -0,0 +1,359 @@ + + + + +1. Introduction + + + + + + + + + + + +
+
+
+

1. Introduction

+
+
+ +

Metaprogramming is usually defined as the creation of programs which generate other programs. Parser generators such as YACC [Joh79] are examples of one kind of program-generating program. The input language to YACC is a context-free grammar in Extended Backus-Naur Form [EBNF], and its output is a program which parses that grammar. Note that in this case the metaprogram (YACC) is written in a language (C) which does not directly support the description of generated programs. These specifications, which we'll call metadata, are not written in C, but in a meta-language. Because the the rest of the user's program typically requires a general-purpose programming system and must interact with the generated parser, the metadata is translated into C, which is then compiled and linked together with the rest of the system. The metadata thus undergoes two translation steps, and the user is always very conscious of the boundary between her metadata and the rest of her program.

+ +
+
+
+

1.1. Native language metaprogramming

+
+
+ +

A more interesting form of metaprogramming is available in languages such as Scheme [SS75], where the generated program specification is given in the same language as the metaprogram itself. The metaprogrammer defines her meta-language as a subset of the expressible forms of the underlying language, and program generation can take place in the same translation step used to process the rest of the user's program. This allows users to switch transparently between ordinary programming, generated program specification, and metaprogramming, often without being aware of the transition.

+
+ +
+
+
+

1.2. Metaprogramming in C++

+
+
+ +

In C++, it was discovered almost by accident [Unr], [Vel95a] that the template mechanism provides a rich facility for computation at compile-time. In this section, we'll explore the basic mechanisms and some common idioms used for metaprogramming in C++.

+ +
+
+
+

1.2.1. Numeric computations

+
+
+ +

The availability of non-type template parameters makes it possible to perform integer computations at compile-time. For example, the following template computes the factorial of its argument:

+ +
+template< unsigned n >
+struct factorial
+{
+    static const unsigned value = n * factorial<n-1>::value;
+};
+
+template<>
+struct factorial<0>
+{
+    static const unsigned value = 1;
+};
+
+ +

The program fragment above is called a metafunction, and it is easy to see its relationship to a function designed to be evaluated at runtime: the ‘metafunction argument’ is passed as a template parameter, and its ‘return value’ is defined as a nested static constant. Because of the hard line between the expression of compile-time and runtime computation in C++, metaprograms look different from their runtime counterparts. Thus, although as in Scheme the C++ metaprogrammer writes her code in the same language as the ordinary program, only a subset of the full C++ language is available to her: those expressions which can be evaluated at compile-time. Compare the above with a straightforward runtime definition of the factorial function:

+ +
+unsigned factorial(unsigned N)
+{
+    return N == 0 ? 1 : N * factorial(N - 1);
+}
+
+ +

While it is easy to see the analogy between the two recursive definitions, recursion is in general more important to C++ metaprograms than it is to runtime C++. In contrast to languages such as Lisp where recursion is idiomatic, C++ programmers will typically avoid recursion when possible. This is done not only for efficiency reasons, but also because of ‘cultural momentum’: recursive programs are simply harder (for C++ programmers) to think about. Like pure Lisp, though, the C++ template mechanism is a functional programming language: as such it rules out the use of data mutation required to maintain loop variables.

+ +

A key difference between the runtime and compile-time factorial functions is the expression of the termination condition: our meta-factorial uses template specialization as a kind of pattern-matching mechanism to describe the behavior when N is zero. The syntactic analogue in the runtime world would require two separate definitions of the same function. In this case the impact of the second definition is minimal, but in large metaprograms the cost of maintaining and understanding the terminating definitions can become significant.

+ +

Note also that a C++ metafunction's return value must be named. The name chosen here, value, is the same one used for all numeric returns in the MPL. As we'll see, establishing a consistent naming convention for metafunction returns is crucial to the power of the library.

+
+ +
+
+
+

1.2.2. Type computations

+
+
+ +

How could we apply our factorial metafunction? We might, for example, produce an array type of an appropriate size to hold all permutations of instances of another type:

+ +
+// permutation_holder<T>::type is an array type which can contain 
+// all permutations of a given T.
+
+// unspecialized template for scalars
+template< typename T >
+struct permutation_holder
+{
+    typedef T type[1][1];
+};
+
+// specialization for array types
+template< typename T, unsigned N >
+struct permutation_holder<T[N]>
+{
+    typedef T type[factorial<N>::value][N];
+};
+
+ +

Here we have introduced the notion of a type computation. Like factorial above, permutation_holder template is a metafunction. However, where factorial manipulates unsigned integer values, permutation_holder accepts and ‘returns’ a type (as the nested typedef type). Because the C++ type system provides a much richer set of expressions than anything we can use as a nontype template argument (e.g. the integers), C++ metaprograms tend to be composed mostly of type computations.

+
+ +
+
+
+

1.2.3. Type sequences

+
+
+ +

The ability to programmatically manipulate collections of types is a central tool of most interesting C++ metaprograms. Because this capability is so well-supported by the MPL, we'll provide just a brief introduction to the basics here. Later on, we'll revisit the example below to show how it can be implemented using MPL.

+ +

First, we'd need a way to represent the collection. One idea might be to store the types in a structure:

+ +
+struct types
+{
+    int t1;
+    long t2;
+    std::vector<double> t3;
+};
+
+ +

Unfortunately, this arrangement is not susceptible to the compile-time type introspection power that C++ gives us: there's no way to find out what the names of the members are, and even if we assume that they're named according to some convention as above, there's no way to know how many members there are. The key to solving this problem is to increase the uniformity of the representation. If we have a consistent way to get the first type of any sequence and the rest of the sequence, we can easily access all members:

+ +
+template< typename First, typename Rest >
+struct cons
+{
+    typedef First first;
+    typedef Rest rest;
+};
+
+struct nil {};
+
+typedef
+      cons<int
+    , cons<long
+    , cons<std::vector<double>
+    , nil
+    > > > my_types;
+
+ +

The structure described by types above is the compile-time analogue of a singly-linked list; it has been first introduced by Czarnecki and Eisenecker in [CE98]. Now that we've adjusted the structure so that the C++ template machinery can ‘peel it apart’, let's examine a simple metafunction which does so. Suppose a user wished to find the largest of an arbitrary collection of types. We can apply the recursive metafunction formula which should by now be familiar:

+ +
+

Example 1. 'largest' metafunction

+ +
+// choose the larger of two types
+template<
+      typename T1
+    , typename T2
+    , bool choose1 = (sizeof(T1) > sizeof(T2)) // hands off!
+    >
+struct choose_larger
+{
+    typedef T1 type;
+};
+
+// specialization for the case where sizeof(T2) >= sizeof(T1)
+template< typename T1, typename T2 >
+struct choose_larger< T1,T2,false >
+{
+    typedef T2 type;
+};
+
+// get the largest of a cons-list
+template< typename T > struct largest;
+
+// specialization to peel apart the cons list
+template< typename First, typename Rest >
+struct largest< cons<First,Rest> >
+    : choose_larger< First, typename largest<Rest>::type >
+{
+    // type inherited from base
+};
+
+// specialization for loop termination
+template< typename First >
+struct largest< cons<First,nil> >
+{
+    typedef First type;
+};
+
+int main()
+{
+    // print the name of the largest of my_types
+    std::cout
+        << typeid(largest<my_types>::type).name()
+        << std::endl
+        ;
+}
+
+
+ +

There are several things worth noticing about this code:

+ +
+
    +
  • +

    It uses a few ad-hoc, esoteric techniques, or ‘hacks’. The default template argument choose1 (labeled ‘hands off!’) is one example. Without it, we would have needed yet another template to provide the implementation of choose_larger, or we would have had to provide the computation explicitly as a parameter to the template - perhaps not bad for this example, but it would make choose_larger much less useful and more error-prone. The other hack is the derivation of a specialization of largest from choose_larger. This is a code-saving device which allows the programmer to avoid writing ‘typedef typename ...::type type’ in the template body.

    +
  • + +
  • +

    Even this simple metaprogram uses three separate partial specializations. The largest metafunction uses two specializations. One might expect that this indicates there are two termination conditions, but there are not: one specialization is needed simply to deal with access to the sequence elements. These specializations make the code difficult to read by spreading the definition of a single metafunction over several C++ template definitions. Also, because they are partial specializations, they make the code unusable for a large community of C++ programmers whose compilers don't support that feature.

    +
  • +
+
+ +

While these techniques are, of course, a valuable part of the arsenal of any good C++ metaprogrammer, their use tends to make programs written in what is already an unusual style harder-to-read and harder-to-write. By encapsulating commonly-used structures and dealing with loop terminations internally, the MPL reduces the need for both tricky hacks and for template specializations.

+
+
+ +
+
+
+

1.3. Why metaprogramming?

+
+
+ +

It's worth asking why anyone would want to do this. After all, even a simple toy example like the factorial metafunction is somewhat esoteric. To show how the type computation can be put to work, let's examine a simple example. The following code produces an array containing all possible permutations of another array:

+ +
+// can't return an array in C++, so we need this wrapper
+template< typename T >
+struct wrapper
+{
+    T x;
+};
+
+// return an array of the N! permutations of 'in'
+template< typename T >
+wrapper< typename permutation_holder<T>::type >
+all_permutations(T const& in)
+{
+    wrapper<typename permutation_holder<T>::type> result;
+
+    // copy the unpermutated array to the first result element
+    unsigned const N = sizeof(T) / sizeof(**result.x);
+    std::copy(&*in, &*in + N, result.x[0]);
+
+    // enumerate the permutations
+    unsigned const result_size = sizeof(result.x) / sizeof(T);
+    for (T* dst = result.x + 1; dst != result.x + result_size; ++dst)
+    {
+        T* src = dst - 1;
+        std::copy(*src, *src + N, *dst);
+        std::next_permutation(*dst, *dst + N);
+    }
+    return result;
+}
+
+ +

The runtime definition of factorial would be useless in all_permutations above, since in C++ the sizes of array members must be computed at compile-time. However, there are alternative approaches; how could we avoid metaprogramming, and what would the consequences be?

+ +
+
    +
  1. +

    We could write programs to interpret the metadata directly. In our factorial example, the array size could have been a runtime quantity; then we'd have been able to use the straightforward factorial function. However, that would imply the use of dynamic allocation, which is often expensive.

    + +

    To carry this further, YACC might be rewritten to accept a pointer-to-function returning tokens from the stream to be parsed, and a string containing the grammar description. This approach, however, would impose unacceptable runtime costs for most applications: either the parser would have to treat the grammar nondeterministically, exploring the grammar for each parse, or it would have to begin by replicating at runtime the substantial table-generation and optimization work of the existing YACC for each input grammar.

    +
  2. + +
  3. +

    We could replace the compile-time computation with our own analysis. After all, the size of arrays passed to all_permutations are always known at compile-time, and thus can be known to its user. We could ask the user to supply the result type explicitly:

    + +
    +template< typename Result, typename T >
    +Result all_permutations(T const& input);
    +
    + +

    The costs to this approach are obvious: we give up expressivity (by requiring the user to explicitly specify implementation details), and correctness (by allowing the user to specify them incorrectly). Anyone who has had to write parser tables by hand will tell you that the impracticality of this approach is the very reason of YACC's existence.

    + +

    In a language such as C++, where the metadata can be expressed in the same language as the rest of the user's program, expressivity is further enhanced: the user can invoke metaprograms directly, without learning a foreign syntax or interrupting the flow of her code.

    +
  4. +
+
+ +

So, the motivation for metaprogramming comes down to the combination of three factors: efficiency, expressivity, and correctness. While in classical programming there is always a tension between expressivity and correctness on one hand and efficiency on the other, in the metaprogramming world we wield new power: we can move the computation required for expressivity from runtime to compile-time.

+
+ +
+
+
+

1.4. Why a metaprogramming library?

+
+
+ +

One might just as well ask why we need any generic library:

+ +
+
    +
  • +

    Quality. Code that is appropriate for a general-purpose library is usually incidental to the purpose of its users. To a library developer, it is the central mission. On average, the containers and algorithms provided by any given C++ standard library implementation are more-flexible and better-implemented than the project-specific implementations which abound, because library development was treated as an end in itself rather than a task incidental to the development of some other application. With a centralized implementation for any given function, optimizations and improvements are more likely to have been applied.

    +
  • + +
  • +

    Re-use. More important even than the re-use of code which all libraries provide, a well-designed generic library establishes a framework of concepts and idioms which establishes a reusable mental model for approaching problems. Just as the C++ Standard Template Library gave us iterator concepts and a function object protocol, the Boost Metaprogramming Library provides type-iterators and metafunction class protocol. A well-considered framework of idioms saves the metaprogrammer from considering irrelevant implementation details and allows her to concentrate on the problem at hand.

    +
  • + +
  • +

    Portability. A good library can smooth over the ugly realities of platform differences. While in theory a metaprogramming library is fully generic and shouldn't be concerned with these issues, in practice support for templates remains inconsistent even four years after standardization. This should perhaps not be surprising: C++ templates are the language's furthest-reaching and most complicated feature, which largely accounts for the power of metaprogramming in C++.

    +
  • + +
  • +

    Fun. Repeating the same idioms over and over is tedious. It makes programmers tired and reduces productivity. Furthermore, when programmers get bored they get sloppy, and buggy code is even more costly than slowly-written code. Often the most useful libraries are simply patterns that have been “plucked” by an astute programmer from a sea of repetition. The MPL helps to reduce boredom by eliminating the need for the most commonly-repeated boilerplate coding patterns.

    +
  • +
+
+ +

As one can see, the MPL's development is motivated primarily by the same practical, real-world considerations that justify the development of any other library. Perhaps this is an indication that template metaprogramming is finally ready to leave the realm of the esoteric and enter the lingua franca of every day programmers.

+
+
+ + + + + diff --git a/doc/paper/html/lambda.html b/doc/paper/html/lambda.html new file mode 100644 index 0000000..7e5bbc2 --- /dev/null +++ b/doc/paper/html/lambda.html @@ -0,0 +1,165 @@ + + + + +3. Lambda facility + + + + + + + + + + + +
+
+
+

3. Lambda facility

+
+
+ +

The MPL's lambda facility allows the inline composition of class templates into ‘lambda expressions’, which are classes and can therefore be passed around as ordinary metafunction classes, or transformed into metafunction classes before application using the expression:

+ +
+typedef mpl::lambda<expr>::type func;
+
+ +

For example, boost::remove_const traits template from Boost type_traits library [TTL] is a class template (obviously), or a metafunction in MPL terminology. The simplest example of an ‘inline composition’ of it would be something like:

+ +
+typedef boost::remove_const<_1> expr;
+
+ +

This forms a so called ‘lambda expression’, which is neither a metafunction class, nor a metafunction, yet can be passed around everywhere because it's an ordinary C++ class, because all MPL facilities are polymorphic with respect to their arguments. Now, that lambda expression can be transformed into a metafunction class using the MPL's lambda facility:

+ +
+typedef boost::remove_const<_1> expr;
+typedef mpl::lambda<expr>::type func;
+
+ +

The func is a unary metafunction class and can be used as such. In particular, it can be pass around or invoked (applied):

+ +
+typedef mpl::apply<func,int const>::type res;
+BOOST_MPL_ASSERT_IS_SAME(res, int);
+
+ +

or even

+ +
+typedef func::apply<int const>::type res;
+BOOST_MPL_ASSERT_IS_SAME(res, int);
+
+ +

Inline composition is very appealing syntactically when one deals with metafunctions, because it makes the expression obvious:

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_1>, mpl::int_c<16> >
+    , boost::is_same<_1,_2>
+    > expr;
+
+typedef mpl::lambda<expr>::type func;
+
+ +

And one does not have to specify the last part (typedef lambda<expr>::type func), because all the algorithms do this to any of their metafunction class operands internally (a lambda<T>::type expression applied to a metafunction class gives back the same metafunction class, so it's safe to apply the expression unconditionally).

+ +

The alternative way to write an equivalent of the above metafunction class would be:

+ +
+typedef bind<
+      mpl::meta_fun2<mpl::logical_or>
+    , mpl::bind< mpl::meta_fun2<mpl::less>
+        , mpl::bind< mpl::meta_fun1<mpl::size_of>,_1 >
+        , mpl::int_c<16>
+        >
+    , mpl::bind< mpl::meta_fun2<boost::is_same>,_1,_2 >
+    > func;
+
+ +

Or to use mpl::compose_ family of templates in a similar way. Here, we use mpl::meta_fun templates to convert metafunctions into metafunction classes and then combine them using mpl::bind. The transformation from this form to the above inline lambda expression and vice-versa is mechanical, and that is essentially what the typedef mpl::lambda<expr>::type expression does.

+ +

For its own metafunctions (algorithms, primitives, etc.), MPL enables one to write the above in a less cumbersome way:

+ +
+typedef mpl::bind<
+      mpl::logical_or<>
+    , mpl::bind< mpl::less<>, mpl::bind<mpl::size_of<>,_1>, mpl::int_c<16> >
+    , mpl::bind< mpl::make_f2<boost::is_same>, _1,_2 >
+    > func;
+
+ +

Note that we still have to wrap is_same into make_f2, because it's a foreign template.

+ +

Now, about combining class template metafunctions and metafunction classes in the single lambda expression - it can be done like this:

+ +
+struct my_predicate
+{
+    template< typename T1, typename T2 > struct apply
+    {
+        //...
+    };
+};
+
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , mpl::bind< my_predicate,_,_ > // here
+    > expr;
+
+ +

To bind something to one of its arguments (or change the order of parameters), then use either:

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , mpl::bind<my_predicate,int,_>::type // here
+    > expr;
+
+ +

or

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , my_predicate::apply<int,_> // here
+    > expr;
+
+
+ + + + + diff --git a/doc/paper/html/refs.html b/doc/paper/html/refs.html new file mode 100644 index 0000000..ae8564f --- /dev/null +++ b/doc/paper/html/refs.html @@ -0,0 +1,152 @@ + + + + +References + + + + + + + + + + +
+
+
+

References

+
+
+ +
+

[Abr01] David Abrahams and Carlos Pinto Coelho, Effects of Metaprogramming Style on Compilation Time, 2001

+
+ +
+

[Ale01] Andrei Alexandrescu, Modern C++ Design: Generic Programming and Design Patterns Applied, Addison-Wesley, ISBN 0-201-70431-5, 2001

+
+ +
+

[CE98] Krzysztof Czarnecki and Ulrich Eisenecker, Metalisp, http://home.t-online.de/home/Ulrich.Eisenecker/meta.htm

+
+ +
+

[CE00] Krzysztof Czarnecki and Ulrich Eisenecker, Generative Programming: Methods, Tools, and Applications, Addison-Wesley, ISBN 0-201-30977-7, 2000

+
+ +
+

[EBNF] ISO/IEC 14977:1996(E), Information technology — Syntactic metalanguage — Extended BNF, ISO/IEC, 1996

+
+ +
+

[GHJ+95] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns, Elements of Reusable Object-Oriented Software, Addison-Wesley, ISBN 0-201-63361-2, 1995

+
+ +
+

[HU79] Hopcroft and Ullman, Introduction to automata theory, languages and computations, Addison-Wesley, 1979

+
+ +
+

[Hud89] Paul Hudak, Conception, Evolution, and Application of Functional Programming Languages, ACM Computing Surveys, Association for Computing Machinery (ACM), ISSN 0360-0300, Vol. 21, No. 3, pp. 359-411, September, 1989

+
+ +
+

[Hun91] Immo Huneke, Finite State Machines: A Model of Behavior for C++, C++ Report, SIGS Publications Inc., ISSN 1040-6042, 1991

+
+ +
+

[ISO98] ISO/IEC 14882:1998(E), Programming languages — C++, ISO/IEC, 1998

+
+ +
+

[Joh79] Stephen C. Johnson, Yacc: Yet Another Compiler Compiler, UNIX Programmer's Manual, Vol. 2b, pp. 353-387, 1979

+
+ +
+

[Laf00] David Lafreniere, State Machine Design in C++, C/C++ User Journal, CMP Media LCC, ISSN 1075-2838, Vol. 18, No. 5, May 1998

+
+ +
+

[Loki] The Loki library, http://sourceforge.net/projects/loki-lib/

+
+ +
+

[Mar98] Robert C. Martin, UML Tutorial: Finite State Machines, C++ Report, SIGS Publications Inc., ISSN 1040-6042, June 1998

+
+ +
+

[MPLR] Boost MPL Library Reference Documentation, http://www.mywikinet.com/mpl/ref/Table_of_Content.html

+
+ +
+

[PRE] Vesa Karvonen, Boost Preprocessor Metaprogramming library, http://www.boost.org/libs/preprocessor/doc/

+
+ +
+

[SMC] Robert C. Martin, SMC - Finite State Machine Compiler (C++), http://www.objectmentor.com/resources/downloads/index

+
+ +
+

[STL94] A. A. Stepanov and M. Lee, The Standard Template Library, Hewlett-Packard Laboratories, 1994

+
+ +
+

[SPL] Boost Smart Pointer library, http://www.boost.org/libs/smart_ptr/

+
+ +
+

[SS75] Gerald J. Sussman and Guy L. Steele Jr., Scheme: An interpreter for extended lambda calculus, MIT AI Memo 349, Massachusetts Institute of Technology, May 1975

+
+ +
+

[TTL] Boost Type Traits library, http://www.boost.org/libs/type_traits/

+
+ +
+

[Vel95a] Todd Veldhuizen, Using C++ template metaprograms, C++ Report, SIGS Publications Inc., ISSN 1040-6042, Vol. 7, No. 4, pp. 36-43, May 1995

+
+ +
+

[Vel95b] Todd Veldhuizen, Expression templates, C++ Report, SIGS Publications Inc., ISSN 1040-6042, Vol. 7, No. 5, pp. 26-31, Jun 1995

+
+ +
+

[Unr] Erwin Unruh, Prime number computation, ANSI X3J16-94-0075/ISO WG21-462

+
+
+ + + + + diff --git a/doc/paper/html/usage.html b/doc/paper/html/usage.html new file mode 100644 index 0000000..6eede7b --- /dev/null +++ b/doc/paper/html/usage.html @@ -0,0 +1,920 @@ + + + + +2. Basic usage + + + + + + + + + + + +
+
+
+

2. Basic usage

+
+
+ +
+
+
+

2.1. Conditional type selection

+
+
+ +

Conditional type selection is the simplest basic construct of C++ template metaprogramming. Veldhuizen [Vel95a] was the first to show how to implement it, and Czarnecki and Eisenecker [CE00] first presented it as a standalone library primitive. The MPL defines the corresponding facility as follows:

+ +
+template<
+      typename Condition
+    , typename T1
+    , typename T2
+    >
+struct if_
+{
+    typedef /*unspecified*/ type;
+};
+
+ +

Note that the first template parameter of the template is a type.

+ +
+// usage/semantics
+typedef mpl::if_<mpl::true_c,char,long>::type t1;
+typedef mpl::if_<mpl::false_c,char,long>::type t2;
+
+BOOST_MPL_ASSERT_IS_SAME(t1, char);
+BOOST_MPL_ASSERT_IS_SAME(t2, long);
+
+ +

The construct is important because template metaprograms often contain a lot of decision-making code, and, as we will show, spelling it manually every time via (partial) class template specialization quickly becomes impractical. The template is also important from the point of encapsulating the compiler workarounds.

+ +
+
+
+

2.1.1. Delayed evaluation

+
+
+ +

The way the C++ template instantiation mechanism works imposes some subtle limitations on applicability of the type selection primitive (if_), compared to a manually implemented equivalent of the selection code. For example, suppose we are implementing a pointed_type traits template such that pointed_type<T>::type instantiated for a T that is either a plain pointer (U*), std::auto_ptr<U>, or any of the Boost smart pointers [SPL], e.g. boost::scoped_ptr<U>, will give us the pointed type (U):

+ +
+BOOST_MPL_ASSERT_IS_SAME(pointed_type<my*>::type, my);
+BOOST_MPL_ASSERT_IS_SAME(pointed_type< std::auto_ptr<my> >::type, my);
+BOOST_MPL_ASSERT_IS_SAME(pointed_type< boost::scoped_ptr<my> >::type, my);
+
+ +

Unfortunately, the straightforward application of if_ to this problem does not work: 1

+ +
+template< typename T >
+struct pointed_type
+    : mpl::if_<
+          boost::is_pointer<T>
+        , typename boost::remove_pointer<T>::type
+        , typename T::element_type // #1
+        >
+{
+};
+
+// the following code causes compilation error in line #1:
+// name followed by "::" must be a class or namespace name
+typedef pointed_type<char*>::type result;
+
+ +

Clearly, the expression typename T::element_type is not valid in the case of T == char*, and that's what the compiler is complaining about. Implementing the selection code manually solves the problem:

+ +
+namespace aux {
+// general case
+template< typename T, bool is_pointer = false >
+struct select_pointed_type
+{
+    typedef typename T::element_type type;
+};
+
+// specialization for plain pointers
+template< typename  T >
+struct select_pointed_type<T,true>
+{
+    typedef typename boost::remove_pointer<T>::type type;
+};
+}
+
+template< typename T >
+struct pointed_type
+   : aux::select_pointed_type<
+          T, boost::is_pointer<T>::value
+        >
+{
+};
+
+ +

But this quickly becomes awkward if needs to be done repeatedly, and this awkwardness is compounded when partial specialization is not available. We can try to work around the problem as follows:

+ +
+namespace aux {
+template< typename T >
+struct element_type
+{
+     typedef typename T::element_type type;
+};
+}
+
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , typename boost::remove_pointer<T>::type
+        , typename aux::element_type<T>::type
+        >::type type;
+};
+
+ +

but this doesn't work either - the access to the aux::element_type<T>'s nested type member still forces the compiler to instantiate element_type<T> with T == char*, and that instantiation is, of course, invalid. Also, although in our case this does not lead to a compile error, the boost::remove_pointer<T> template always gets instantiated as well, and for the same reason (because we are accessing its nested type member). Unnecessary instantiation that is not fatal may or may be not a problem, depending on the ‘weight’ of the template (how much the instantiation taxes the compiler), but a general rule of thumb would be to avoid such code.

+ +

Returning to our error, to make the above code compile, we need to factor the act of ‘asking’ aux::element_type<T> for its nested type out of the if_ invocation. The fact that both the boost::remove_pointer<T> trait template and aux::element_type<T> use the same naming convention for their result types makes the refactoring easier:

+ +
+template< typename T >
+struct pointed_type
+{
+ private:
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type func_;
+
+ public:
+    typedef typename func_::type type;
+};
+
+ +

Now the compiler is guaranteed not to instantiate both boost::remove_pointer<T> and aux::element_type<T>, even although they are used as actual parameters to the if_ template, so we are allowed to get away with aux::element_type<char*> so long as it won't end up being selected as func_.

+ +

The above technique is so common in template metaprograms, that it even makes sense to facilitate the selection of a nested type member by introducing a high-level equivalent to if_ - the one that will do the func_::type operation (that is called [nullary] metafunction class application) as a part of its invocation. The MPL provides such template - it's called apply_if. Using it, we can re-write the above code as simple as:

+ +
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::apply_if<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type type;
+};
+
+ +

To make our techniques review complete, let's consider a slightly different example - suppose we want to define a high-level wrapper around boost::remove_pointer traits template [TTL], which will strip the pointer qualification conditionally. We will call it remove_pointer_if:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::if_<
+          Condition
+        , typename boost::remove_pointer<T>::type
+        , T
+        >::type type;
+};
+
+ +

Now the above works the first time, but it suffers from the problem we mentioned earlier - boost::remove_pointer<T> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource [Abr01], and it is wasted by unnecessary template instantiations. We've just seen how to deal with the problem when both arguments to if_ are the results of nullary metafunction class applications, but in this example one of the arguments (T) is just a simple type, so the refactoring just doesn't seem possible.

+ +

The easiest way out of this situation would be to pass to if_ a real nullary metafunction instead of T - the one that returns T on its invocation. The MPL provides a simple way to do it - we just substitute identity<T> and apply_if for T and if_:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::apply_if<
+          Condition
+        , boost::remove_pointer<T>
+        , mpl::identity<T>
+        >::type type;
+};
+
+ +

which gives us exactly what we wanted.

+
+
+ +
+
+
+

2.2. Metafunctions

+
+
+ +
+
+
+

2.2.1. The simple form

+
+
+ +

In C++, the basic underlying language construct which allows parameterized compile-time computation is the class template ([ISO98], section 14.5.1 [temp.class]). A bare class template is the simplest possible model we could choose for metafunctions: it can take types and/or non-type arguments as actual template parameters, and instantiation ‘returns’ a new type. For example, the following produces a type derived from its arguments:

+ +
+template< typename T1, typename T2 >
+struct derive : T1, T2
+{
+};
+
+ +

However, this model is far too limiting: it restricts the metafunction result not only to class types, but to instantiations of a given class template, to say nothing of the fact that every metafunction invocation introduces an additional level of template nesting. While that might be acceptable for this particular metafunction, any model which prevented us from ‘returning’, say, int is obviously not general enough. To meet this basic requirement, we must rely on a nested type to provide our return value:

+ +
+template< typename T1, typename T2 >
+struct derive
+{
+    struct type : N1, N2 {};
+};
+
+// silly specialization, but demonstrates "returning" int
+template<>
+struct derive<void,void>
+{
+    typedef int type;
+};
+
+ +

Veldhuizen [Vel95a] was first to talk about class templates of this form as ‘compile-time functions’, and Czarnecki and Eisenecker [CE00] have introduced ‘template metafunction’ as an equivalent term (they also use the simpler term ‘metafunction’, as do we). Czarnecki and Eisenecker have also recognized the limitations of the simple metafunction representation and suggested the form that we discuss in Section 2.2.3.

+
+ +
+
+
+

2.2.2. Higher-order metafunctions

+
+
+ +

While syntactically simple, the simple template metafunction form does not always interact optimally with the rest of C++. In particular, the simple metafunction form makes it unnecessarily awkward and tedious to define and work with higher-order metafunctions (metafunctions that operate on other metafunctions). In order to pass a simple metafunction to another template, we need to use template template parameters:

+ +
+// returns F(T1,F(T2,T3))
+template<
+      template<typename> class F
+    , typename T1
+    , typename T2
+    , typename T3
+    >
+struct apply_twice
+{
+  typedef typename F<
+        T1
+      , typename F<T2,T3>::type
+      >::type type;
+};
+
+// a new metafunction returning a type derived from T1, T2, and T3
+template<
+      typename T1
+    , typename T2
+    , typename T3
+    >
+struct derive3
+    : apply_twice<derive,T1,T2,T3>
+{
+};
+
+ +

This looks different, but it seems to work. 2 However, things begin to break down noticeably when we want to ‘return’ a metafunction from our metafunction:

+ +
+// returns G s.t. G(T1,T2,T3) == F(T1,F(T2,T3))
+template< template<typename> class F >
+struct compose_self
+{
+    template<
+          typename T1
+        , typename T2
+        , typename T3
+        > 
+    struct type
+        : apply_twice<F,T1,T2,T3>
+    {
+    };
+};
+
+ +

The first and most obvious problem is that the result of applying compose_self is not itself a type, but a template, so it can't be passed in the usual ways to other metafunctions. A more subtle issue, however, is that the metafunction ‘returned’ is not exactly what we intended. Although it acts just like apply_twice, it differs in one important respect: its identity. In the C++ type system, compose_self<F>::template type<T,U,V> is not a synonym for apply_twice<F,T,U,V>, and any metaprogram which compared metafunctions would discover that fact.

+ +

Because C++ makes a strict distinction between type and class template template parameters, reliance on simple metafunctions creates a ‘wall’ between metafunctions and metadata, relegating metafunctions to the status of second-class citizens. For example, recalling our introduction to type sequences, there's no way to make a cons list of metafunctions:

+ +
+typedef cons<derive, cons<derive3, nil> > derive_functions; // error!
+
+ +

We might consider redefining our cons cell so we can pass derive as the head element:

+ +
+template <
+      template< template<typename T, typename U> class F
+    , typename Tail
+    >
+struct cons;
+
+ +

However, now we have another problem: C++ templates are polymorphic with respect to their type arguments, but not with respect to template template parameters. The arity (number of parameters) of any template template parameter is strictly enforced, so we still can't embed derive3 in a cons list. Moreover, polymorphism between types and metafunctions is not supported (the compiler expects one or the other), and as we've seen, the syntax and semantics of ‘returned’ metafunctions is different from that of returned types. Trying to accomplish everything with the simple template metafunction form would seriously limit the applicability of higher-order metafunctions and would have an overall negative effect on the both conceptual and implementation clarity, simplicity and size of the library.

+
+ +
+
+
+

2.2.3. Metafunction classes

+
+
+ +

Fortunately, the truism that ‘there is no problem in software which can't be solved by adding yet another level of indirection’ applies here. To elevate metafunctions to the status of first-class objects, the MPL introduces the concept of a ‘metafunction class’:

+ +
+// metafunction class form of derive
+struct derive
+{
+    template< typename N1, typename N2 >
+    struct apply
+    {
+        struct type : N1, N2 {};
+    };
+};
+
+ +

This form should look familiar to anyone acquainted with function objects in STL, with the nested apply template taking the same role as the runtime function-call operator. In fact, compile-time metafunction classes have the same relationship to metafunctions that runtime function objects have to functions:

+ +
+// function form of add
+template< typename T > T add(T x, T y) { return x + y; }
+
+// function object form of add
+struct add
+{
+    template< typename T >
+    T operator()(T x, T y) { return x + y; }
+};
+
+
+ +
+
+
+

2.2.4. One size fits all?

+
+
+ +

The metafunction class form solves all the problems with ordinary template metafunction mentioned earlier: since it is a regular class, it can be placed in compile-time metadata sequences and manipulated by other metafunctions using the same protocols as for any other metadata. We thereby avoid the code-duplication needed to provide versions of each library component to operate on ordinary metadata and on metafunctions with each distinct supported arity.

+ +

On the other hand, it seems that accepting metafunction classes as the representation for compile-time function entities imposes code duplication danger as well: if the library's own primitives, algorithms, etc. are represented as class templates, that means that one either cannot reuse these algorithms in the context of higher-order functions, or she have to duplicate all algorithms in the second form, so, for instance, there would be two versions of find:

+ +
+// user-friendly form
+template<
+      typename Sequence
+    , typename T
+    >
+struct find
+{
+    typedef /* ... */ type;
+};
+
+// "metafunction class" form
+struct find_func
+{
+    template< typename Sequence, typename T >
+    struct apply
+    {
+        typedef /* ... */ type;
+    };
+};
+
+ +

Of course, the third option is to eliminate ‘user-friendly form’ completely so one would always have to write:

+ +
+typedef mpl::find::apply<list,long>::type iter;
+// or, if one prefers,
+// typedef mpl::apply< mpl::find,list,long >::type iter;
+
+ +

instead of

+ +
+typedef mpl::find<list,long>::type iter;
+
+ +

That too would hurt usability, considering that the direct invocations of library's algorithms are far more often-used than passing algorithms as arguments to other algorithms/metafunctions.

+
+ +
+
+
+

2.2.5. From metafunction to metafunction class

+
+
+ +

The MPL's answer to this dilemma is lambda expressions. Lambda is the mechanism that enables the library to curry metafunctions and convert them into metafunction classes, so when one wants to pass the find algorithm as an argument to a higher-order metafunction, she just write:

+ +
+using namespace mpl::placeholder;
+typedef mpl::apply< my_f, mpl::find<_1,_2> >::type result;
+
+ +

where _1 and _2 are placeholders for the first and second arguments to the resulting metafunction class. This preserves the intuitive syntax below for when the user wants to use find directly in her code:

+ +
+typedef mpl::find<list,long>::type iter;
+
+ +

Lambda facility is described in more details in Section 3.

+
+
+ +
+
+
+

2.3. Sequences, algorithms, and iterators

+
+
+ +
+
+
+

2.3.1. Introduction

+
+
+ +

Compile-time iteration over a sequence (of types) is one of the basic concepts of template metaprogramming. Differences in types of objects being manipulated is the most common point of variability of similar but not identical code/design, and such designs are the direct target for some metaprogramming. Templates were originally designed to solve this exact problem (e.g. std::vector). However, without predefined abstractions/constructs for manipulating/iterating over sequences of types (as opposed to standalone types), and without known techniques for emulating these constructs using the current language facilities, their effect on helping high-level metaprogramming happen has been limited.

+ +

Czarnecki and Eisenecker [CE98], [CE00] were the first to introduce compile-time sequences of types and some simple algorithms on them, although the idea of representing common data structures like trees, lists, etc. at compile time, using class template composition has been around for a while (e.g. most of the expression template libraries build such trees as a part of their expression "parsing" process [Vel95b]). Alexandrescu [Ale01] used lists of types and some algorithms on them to implement several design patterns; the accompanying code is known as the Loki library [Loki].

+
+ +
+
+
+

2.3.2. Algorithms and sequences

+
+
+ +

Most of the algorithms in the Boost Metaprogramming Library operate on sequences. For example, searching for a type in a list looks like this:

+ +
+typedef mpl::list<char,short,int,long,float,double> types;
+typedef mpl::find<types,long>::type iter;
+
+ +

Here, find accepts two parameters - a sequence to search (types) and the type to search for (long) - and returns an iterator iter pointing to the first element of the sequence such that iter::type is identical to long. If no such element exists, iter is identical to end<types>::type. Basically, this is how one would search for a value in a std::list or std::vector, except that mpl::find accepts the sequence as a single parameter, while std::find takes two iterators. Everything else is pretty much the same - the names are the same, the semantics are very close, there are iterators, and one can search not only by type, but also by using a predicate:

+ +
+typedef mpl::find_if< types,boost::is_float<_> >::type iter;
+
+ +

This conceptual/syntactical similarity with the STL is not coincidental. Reusing the conceptual framework of the STL in the compile-time world allows us to apply familiar and sound approaches for dealing with sequential data structures. The algorithms and idioms which programmers already know from the STL can be applied again at compile-time. We consider this to be one of MPL's greatest strengths, distinguishing it from earlier attempts to build a template metaprogramming library.

+
+ +
+
+
+

2.3.3. Sequence concepts

+
+
+ +

In the find example above, we searched for the type in a sequence built using the mpl::list template; but list is not the only sequence that the library provides. Neither is mpl::find or any other algorithm hard-coded to work only with list sequences. list is just one model of MPL's Forward Sequence concept, and find works with anything that satisfies this concept's requirements. The hierarchy of sequence concepts in MPL is quite simple - a Sequence is any compile-time entity for which begin<> and end<> produce iterators to the range of its elements; a Forward Sequence is a Sequence whose iterators satisfy Forward Iterator requirements; a Bidirectional Sequence is a Forward Sequence whose iterators satisfy Bidirectional Iterator requirements; finally, a Random Access Sequence is a Bidirectional Sequence whose iterators satisfy Random Access Iterator requirements. 3

+ +

Decoupling algorithms from particular sequence implementations (through iterators) allows a metaprogrammer to create her own sequence types and to retain the rest of the library at her disposal. For example, one can define a tiny_list for dealing with sequences of three types as follows:

+ +
+template< typename TinyList, long Pos >
+struct tiny_list_item;
+
+template< typename TinyList, long Pos >
+struct tiny_list_iterator
+{
+    typedef typename tiny_list_item<TinyList,Pos>::type type;
+    typedef tiny_list_iterator<TinyList, Pos-1> prior;
+    typedef tiny_list_iterator<TinyList, Pos+1> next;
+};
+
+template< typename T0, typename T1, typename T2 >
+struct tiny_list
+{
+    typedef tiny_list_iterator<tiny_list, 0> begin;
+    typedef tiny_list_iterator<tiny_list, 3> end;
+    typedef T0 type0;
+    typedef T1 type1;
+    typedef T2 type2;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,0>
+{
+    typedef typename TinyList::type0 type;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,1>
+{
+    typedef typename TinyList::type1 type;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,2>
+{
+    typedef typename TinyList::type2 type;
+};
+
+ +

and then use it with any of the library algorithms as if it were mpl::list:

+ +
+typedef tiny_list< char,short,int > types;
+typedef mpl::transform<
+      types
+    , boost::add_pointer<_1>
+    >::type pointers;
+
+ +

Note that tiny_list is a model of Bidirectional Sequence; it would be a Random Access Sequence if we added advance and distance members to tiny_list_iterator:

+ +
+template< typename TinyList, long Pos >
+struct tiny_list_iterator
+{
+    static long const position = Pos;
+
+    typedef typename tiny_list_item<TinyList,Pos>::type type;
+    typedef tiny_list_iterator<TinyList, Pos-1> prior;
+    typedef tiny_list_iterator<TinyList, Pos+1> next;
+
+    template< typename N > struct advance
+    {
+        typedef tiny_list_iterator<
+              TinyList
+            , Pos + N::value
+            > type;
+    };
+
+    template< typename Other > struct distance
+    {
+        typedef mpl::integral_c<
+              long
+            , Other::position - position
+            > type;
+    };
+};
+
+ +

While the tiny_list itself might be not that interesting (after all, it can hold only three elements), if the technique above could be automated so we would be able to define not-so-tiny sequences (with five, ten, twenty, etc. elements), it would be very valuable. 4

+ +

External code generation is an option, but there exists a solution within the language. However, it is not a template metaprogramming, but rather preprocessor metaprogramming. In fact, MPL's vector - a fixed-size type sequence that provides random-access iterators - is implemented very much like the above tiny_list - using the Boost Preprocessor library [PRE].

+
+ +
+
+
+

2.3.4. Ad hoc example revisited

+
+
+ +

So, the library provides its users with almost complete compile-time equivalent of the STL framework. Does it help them to solve their metaprogramming tasks? Let's return to our earlier largest example to see if we can rewrite it in a better way with what MPL has to offer. Well, actually, there is not much to look at, because the MPL implementation is a one-liner (we'll spread it out here for readability) 5 :

+ +
+template< typename Sequence >
+struct largest
+{
+    typedef typename mpl::max_element<
+          Sequence
+          mpl::less<
+              mpl::size_of<_1>
+            , mpl::size_of<_2>
+            >
+        >::type iter;
+
+    typedef typename iter::type type;
+};
+
+ +

There are no more termination conditions with tricky pattern matching, no more partial specializations; and even more importantly, it's obvious what the above code does - even although it's all templates - something that one could not say about the original version.

+
+ +
+
+
+

2.3.5. iter_fold as the main iteration algorithm

+
+
+ +

For the purpose of examining a little bit more of the library's internal structure, let's look at how max_element from the above example is implemented. One might expect that now we will again see all these awkward partial specializations, esoteric pattern matching, etc. Well, let's see:

+ +
+template<
+      typename Sequence
+    , typename Predicate
+    >
+struct max_element
+{
+    typedef typename mpl::iter_fold<    
+          Sequence
+        , typename mpl::begin<Sequence>::type
+        , if_< less< deref<_1>,deref<_2> >, _2, _1 >
+        >::type type;
+};
+
+ +

The first thing to notice here is that this algorithm is implemented in terms of another one: iter_fold. In fact, this is probably the most important point of the example, because nearly all other generic sequence algorithms in the library are implemented in terms of iter_fold. If a user should ever need to implement her own sequence algorithm, she'll almost certainly be able to do so using this primitive, which means she won't have to resort to implementing hand-crafted iteration, pattern matching of special cases for loop termination, or workarounds for lack of partial specialization. It also means that her algorithm will automatically benefit from any optimizations the library has implemented, (e.g. recursion unrolling), and that it will work with any sequence that is a model of ForwardSequence, because iter_fold does not require anything more of its sequence argument.

+ +

iter_fold algorithm is basically a compile-time equivalent of the fold or reduce functions that comprise the basic and well-known primitives of many functional programming languages. An analogy more familiar to a C++ programmer would be the std::accumulate algorithm from the C++ standard library ([ISO98], section 26.4.1 [lib.accumulate]). However, iter_fold is designed to take advantage of the natural characteristics of recursive traversal: it accepts two metafunction class arguments, the first of which is applied to the state "on the way in" and the second of which is applied "on the way out".

+ +

The interface to iter_fold is defined in MPL as follows:

+ +
+template<
+      typename Sequence
+    , typename InitialState
+    , typename ForwardOp
+    , typename BackwardOp = _1
+    >
+struct iter_fold
+{
+    typedef /*unspecified*/ type;
+};
+
+ +

The algorithm ‘returns’ the result of two-way successive applications of binary ForwardOp and BackwardOp operations to iterators in range [begin<Sequence>::type, end<Sequence>::type) and previous result of an operation; the InitialState is logically placed before the sequence and included in the forward traversal. The result type is identical to InitialState if the sequence is empty.

+ +

The library also provides iter_fold_backward, fold, and fold_backward algorithms which wrap iter_fold to accommodate its most common usage patterns.

+
+ +
+
+
+

2.3.6. Sequences of numbers

+
+
+ +

What we've seen so far were sequences (and algorithms on sequences) of types. It is both possible and easy to manipulate compile-time values using the library as well. The only thing to remember is that in C++, class template non-type template parameters give us one more example of non-polymorphic behavior. In other words, if one declared a metafunction to take a non-type template parameter (e.g. long) it's not possible to pass anything besides compile-time integral constants to it:

+ +
+template< long N1, long N2 >
+struct equal_to
+{
+    static bool const value = (N1 == N2);
+};
+
+equal_to<5,5>::value; // ok
+equal_to<int,int>::value; // error!
+
+ +

And of course this doesn't work the other way around either:

+ +
+typedef mpl::list<1,2,3,4,5> numbers; // error!
+
+ +

While this may be an obvious limitation, it imposes yet another dilemma on the library design: on the one hand, we don't want to restrict users to type manipulations only, and on the other hand, full support for integral manipulations would require at least duplication of most of the library facilities 6 - the same situation as we would have if we had chosen to represent metafunctions as ordinary class templates. The solution for this issue is the same as well: we represent integral values by wrapping them in types 7 . For example, to create a list of numbers one can write:

+ +
+typedef mpl::list<
+      mpl::int_c<1>
+    , mpl::int_c<2>
+    , mpl::int_c<3>
+    , mpl::int_c<4>
+    , mpl::int_c<5>
+    > numbers;
+
+ +

Wrapping integral constants into types to make them first-class citizens is important well inside metaprograms, where one often doesn't know (and doesn't care) if the metafunctions she is using operate on types, integral values, other metafunctions, or something else, like fixed-point or rational numbers (mpl::fixed_c and mpl::rational_c).

+ +

But, from the user's perspective, the above example is much more verbose than the shorter, incorrect one. Thus, for the purpose of convenience, the library does provide users with a template that takes non-type template parameters, but offers a more compact notation:

+ +
+typedef mpl::list_c<long,1,2,3,4,5> numbers;
+
+ +

There is a similar vector counterpart as well:

+ +
+typedef mpl::vector_c<long,1,2,3,4,5> numbers;
+
+
+ +
+
+
+

2.3.7. A variety of sequences

+
+
+ +

Previous efforts to provide generalized metaprogramming facilities for C++ have always concentrated on cons-style type lists and a few core algorithms like size and at, which are tied to the specific sequence implementation. Such systems have an elegant simplicity reminiscent of the analogous functionality in pure functional Lisp. It is much more time-consuming to implement even a basic set of the sequence algorithms provided by equivalent run-time libraries (the STL in particular), but if we have learned anything from the STL, it is that tying those algorithms' implementations to a specific sequence implementation is a misguided effort!

+ +

The truth is that there is no single ‘best’ type sequence implementation for the same reasons that there will never be a single ‘best’ runtime sequence implementation. Furthermore, there are already quite a number of type list implementations in use today; and just as the STL algorithms can operate on sequences which don't come from STL containers, so the MPL algorithms are designed to work with foreign type sequences.

+ +

It may be an eye-opening fact for some that type lists are not the only useful compile-time sequence. Again, the need for a variety of compile-time containers arises for the same reasons that we have lists, vectors, deques, and sets in the C++ standard library - different containers have different functional and performance characteristics which determine not only applicability and efficiency of particular algorithms, but also the expressiveness or verbosity of the code that uses them. While runtime performance is not an issue for C++ metaprograms, compilation speed is often a significant bottleneck to advanced C++ software development [Abr01].

+ +

The MPL provides five built-in sequences: list, list_c (really just a list of value wrappers), vector, a randomly-accessible sequence of fixed maximum size, vector_c, and range_c, a randomly-accessible sequence of consecutive integral values. More important, however, is its ability to adapt to arbitrary sequence types. The only core operations that a sequence is required to provide in order to be used with the library algorithms are begin<> and end<> metafunctions which "return" iterators into the sequence. As with the STL, it is the iterators which are used to implement most of the general-purpose sequence algorithms the library provides. Also, as with the STL, algorithm specialization is used to take advantage of implementation knowledge about particular sequences: many of the "basic" sequence operations such as back<>, front<>, size<>, and at<> are specialized on sequence type to provide a more efficient implementation than the fully generic version.

+
+ +
+
+
+

2.3.8. Loop/recursion unrolling

+
+
+ +

Almost coincidentally, loop unrolling can be as important to compile-time iterative algorithms as it is to runtime algorithms. To see why, one must first remember that all "loops" in C++ metaprograms, are in fact, implemented with recursion, and that the template instantiation depth can be a valuable resource in a compiler implementation. In fact, Annex B of the C++ standard ([ISO98], annex B [limits]) recommends a minimum depth of 17 recursively nested template instantiations; but this is far too low for many serious metaprograms, some of which easily exceed the hard-coded instantiation limits of some otherwise excellent compilers. To see how this works in action, let's examine a straightforward implementation of the fold metafunction, which combines some algorithm state with each element of a sequence:

+ +
+namespace aux {
+
+// unspecialized version combines the initial state and first element
+// and recurses to process the rest
+template<
+      typename Start
+    , typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl
+  : fold_impl<
+        typename Start::next
+      , Finish
+      , typename apply<
+              BinaryFunction
+            , State
+            , typename Start::type
+            >::type
+      , BinaryFunction
+      >
+{
+};
+
+// specialization for loop termination
+template<
+      typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl<Finish,Finish,State,BinaryFunction>
+{
+    typedef State type;
+};
+
+} // namespace aux
+
+// public interface
+template<
+      typename Sequence
+    , typename State
+    , typename ForwardOp
+    >
+struct fold
+    : aux::fold_impl<
+        , typename begin<Sequence>::type
+        , typename end<Sequence>::type
+        , State
+        , typename lambda<ForwardOp>::type
+        >
+{
+};
+
+ +

Although simple and elegant, this implementation will always incur at least as many levels of recursive template instantiation as there are elements in the input sequence. 8 The library addresses this problem by explicitly "unrolling" the recursion. To apply the technique to our fold example, we begin by factoring out a single step of the algorithm. Our fold_impl_step metafunction has two results: type (the next state), and iterator (the next sequence position).

+ +
+template<
+      typename BinaryFunction
+    , typename State
+    , typename Start
+    , typename Finish
+    >
+struct fold_impl_step
+{
+    typedef typename apply<
+          BinaryFunction
+        , State
+        , typename Start::type
+        >::type type;
+
+    typedef typename Start::next iterator;
+};
+
+ +

As with our main algorithm implementation, we specialize for the loop termination condition so that the step becomes a no-op:

+ +
+template<
+      typename BinaryFunction
+    , typename State
+    , typename Finish
+    >
+struct fold_impl_step<BinaryFunction,State,Finish,Finish>
+{
+    typedef State type;
+    typedef Finish iterator;
+};
+
+ +

Now we can now reduce fold's instantiation depth by any constant factor N simply by inserting N invocations of fold_impl_step. Here we've chosen a factor of 4:

+ +
+template<
+      typename Start
+    , typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl
+{
+ private:
+    typedef fold_impl_step<
+        BinaryFunction
+      , State
+      , Start
+      , Finish
+      > next1;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next1::type
+      , typename next1::iterator
+      , Finish
+      > next2;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next2::type
+      , typename next2::iterator
+      , Finish
+      > next3;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next3::type
+      , typename next3::iterator
+      , Finish
+      > next4;
+    
+    typedef fold_impl_step<
+          typename next4::iterator
+        , Finish
+        , typename next4::type
+        , BinaryFunction
+        > recursion;
+
+ public:
+    typedef typename recursion::type type;
+};
+
+ +

The MPL applies this unrolling technique across all algorithms with an unrolling factor tuned according to the demands of the C++ implementation in use, and with an option for the user to override the value. 9 This fact enables users to push beyond the metaprogramming limits they would usually encounter with more naive algorithm implementations. Experiments also show a small (up to 10%) increase in metaprogram instantiation speed on some compilers when loop unrolling is used.

+
+
+
+ + + + + diff --git a/doc/paper/html/xsltproc_build.bat b/doc/paper/html/xsltproc_build.bat new file mode 100755 index 0000000..7e91c0b --- /dev/null +++ b/doc/paper/html/xsltproc_build.bat @@ -0,0 +1,11 @@ +@echo off + +if "%4" == "" goto build +f:\msxsl\msxsl.exe f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\titlepage.templates.xml f:\home\depot\xml\stylesheets\docbook-1.50.0\template\titlepage.xsl | f:\msxsl\msxsl.exe - f:\msxsl\to_utf8.xsl -o f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\titlepage.templates.xsl + +:build +sx -x lower -x empty %2 >%3.xml +xsltproc -o %3 f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\my\%1 %3.xml +del %3.xml +f:\tidy\tidy.exe -config f:\tidy\config.txt -m %3 +f:\tidy\tidy_attr.py %3 diff --git a/doc/paper/mpl_paper.html b/doc/paper/mpl_paper.html new file mode 100644 index 0000000..9ca186d --- /dev/null +++ b/doc/paper/mpl_paper.html @@ -0,0 +1,1957 @@ + + + + +The Boost C++ Metaprogramming Library + + + + + +
+
+
+
+

The Boost C++ Metaprogramming Library

+
+
+ +
+
+

Aleksey Gurtovoyi and David Abrahamsii

+ +
i MetaCommunications, agurtovoy@meta-comm.com
+ +
ii Boost Consulting, david.abrahams@rcn.com
+
+
+ +
+
+

Abstract

+ +

This paper describes the Boost C++ template metaprogramming library (MPL), an extensible compile-time framework of algorithms, sequences and metafunction classes. The library brings together important abstractions from the generic and functional programming worlds to build a powerful and easy-to-use toolset which makes template metaprogramming practical enough for the real-world environments. The MPL is heavily influenced by its run-time equivalent - the Standard Template Library (STL), a part of the C++ standard library [STL94], [ISO98]. Like the STL, it defines an open conceptual and implementation framework which can serve as a foundation for future contributions in the domain. The library's fundamental concepts and idioms enable the user to focus on solutions without navigating the universe of possible ad-hoc approaches to a given metaprogramming problem, even if no actual MPL code is used. The library also provides a compile-time lambda expression facility enabling arbitrary currying and composition of class templates, a feature whose runtime counterpart is often cited as missing from the STL. This paper explains the motivation, usage, design, and implementation of the MPL with examples of its real-life applications, and offers some lessons learned about C++ template metaprogramming.

+
+
+ +
+
+

Keywords: template metaprogramming, generic programming, programming languages, C++, STL, type systems, polymorphism, compile-time

+
+
+
+ + + +
+
+
+

1. Introduction

+
+
+ +

Metaprogramming is usually defined as the creation of programs which generate other programs. Parser generators such as YACC [Joh79] are examples of one kind of program-generating program. The input language to YACC is a context-free grammar in Extended Backus-Naur Form [EBNF], and its output is a program which parses that grammar. Note that in this case the metaprogram (YACC) is written in a language (C) which does not directly support the description of generated programs. These specifications, which we'll call metadata, are not written in C, but in a meta-language. Because the the rest of the user's program typically requires a general-purpose programming system and must interact with the generated parser, the metadata is translated into C, which is then compiled and linked together with the rest of the system. The metadata thus undergoes two translation steps, and the user is always very conscious of the boundary between her metadata and the rest of her program.

+ +
+
+
+

1.1. Native language metaprogramming

+
+
+ +

A more interesting form of metaprogramming is available in languages such as Scheme [SS75], where the generated program specification is given in the same language as the metaprogram itself. The metaprogrammer defines her meta-language as a subset of the expressible forms of the underlying language, and program generation can take place in the same translation step used to process the rest of the user's program. This allows users to switch transparently between ordinary programming, generated program specification, and metaprogramming, often without being aware of the transition.

+
+ +
+
+
+

1.2. Metaprogramming in C++

+
+
+ +

In C++, it was discovered almost by accident [Unr], [Vel95a] that the template mechanism provides a rich facility for computation at compile-time. In this section, we'll explore the basic mechanisms and some common idioms used for metaprogramming in C++.

+ +
+
+
+

1.2.1. Numeric computations

+
+
+ +

The availability of non-type template parameters makes it possible to perform integer computations at compile-time. For example, the following template computes the factorial of its argument:

+ +
+template< unsigned n >
+struct factorial
+{
+    static const unsigned value = n * factorial<n-1>::value;
+};
+
+template<>
+struct factorial<0>
+{
+    static const unsigned value = 1;
+};
+
+ +

The program fragment above is called a metafunction, and it is easy to see its relationship to a function designed to be evaluated at runtime: the “metafunction argument” is passed as a template parameter, and its “return value” is defined as a nested static constant. Because of the hard line between the expression of compile-time and runtime computation in C++, metaprograms look different from their runtime counterparts. Thus, although as in Scheme the C++ metaprogrammer writes her code in the same language as the ordinary program, only a subset of the full C++ language is available to her: those expressions which can be evaluated at compile-time. Compare the above with a straightforward runtime definition of the factorial function:

+ +
+unsigned factorial(unsigned N)
+{
+    return N == 0 ? 1 : N * factorial(N - 1);
+}
+
+ +

While it is easy to see the analogy between the two recursive definitions, recursion is in general more important to C++ metaprograms than it is to runtime C++. In contrast to languages such as Lisp where recursion is idiomatic, C++ programmers will typically avoid recursion when possible. This is done not only for efficiency reasons, but also because of “cultural momentum”: recursive programs are simply harder (for C++ programmers) to think about. Like pure Lisp, though, the C++ template mechanism is a functional programming language: as such it rules out the use of data mutation required to maintain loop variables.

+ +

A key difference between the runtime and compile-time factorial functions is the expression of the termination condition: our meta-factorial uses template specialization as a kind of pattern-matching mechanism to describe the behavior when N is zero. The syntactic analogue in the runtime world would require two separate definitions of the same function. In this case the impact of the second definition is minimal, but in large metaprograms the cost of maintaining and understanding the terminating definitions can become significant.

+ +

Note also that a C++ metafunction's return value must be named. The name chosen here, value, is the same one used for all numeric returns in the MPL. As we'll see, establishing a consistent naming convention for metafunction returns is crucial to the power of the library.

+
+ +
+
+
+

1.2.2. Type computations

+
+
+ +

How could we apply our factorial metafunction? We might, for example, produce an array type of an appropriate size to hold all permutations of instances of another type:

+ +
+// permutation_holder<T>::type is an array type which can contain 
+// all permutations of a given T.
+
+// unspecialized template for scalars
+template< typename T >
+struct permutation_holder
+{
+    typedef T type[1][1];
+};
+
+// specialization for array types
+template< typename T, unsigned N >
+struct permutation_holder<T[N]>
+{
+    typedef T type[factorial<N>::value][N];
+};
+
+ +

Here we have introduced the notion of a type computation. Like factorial above, permutation_holder template is a metafunction. However, where factorial manipulates unsigned integer values, permutation_holder accepts and “returns” a type (as the nested typedef type). Because the C++ type system provides a much richer set of expressions than anything we can use as a nontype template argument (e.g. the integers), C++ metaprograms tend to be composed mostly of type computations.

+
+ +
+
+
+

1.2.3. Type sequences

+
+
+ +

The ability to programmatically manipulate collections of types is a central tool of most interesting C++ metaprograms. Because this capability is so well-supported by the MPL, we'll provide just a brief introduction to the basics here. Later on, we'll revisit the example below to show how it can be implemented using MPL.

+ +

First, we'd need a way to represent the collection. One idea might be to store the types in a structure:

+ +
+struct types
+{
+    int t1;
+    long t2;
+    std::vector<double> t3;
+};
+
+ +

Unfortunately, this arrangement is not susceptible to the compile-time type introspection power that C++ gives us: there's no way to find out what the names of the members are, and even if we assume that they're named according to some convention as above, there's no way to know how many members there are. The key to solving this problem is to increase the uniformity of the representation. If we have a consistent way to get the first type of any sequence and the rest of the sequence, we can easily access all members:

+ +
+template< typename First, typename Rest >
+struct cons
+{
+    typedef First first;
+    typedef Rest rest;
+};
+
+struct nil {};
+
+typedef
+      cons<int
+    , cons<long
+    , cons<std::vector<double>
+    , nil
+    > > > my_types;
+
+ +

The structure described by types above is the compile-time analogue of a singly-linked list; it has been first introduced by Czarnecki and Eisenecker in [CE98]. Now that we've adjusted the structure so that the C++ template machinery can “peel it apart”, let's examine a simple metafunction which does so. Suppose a user wished to find the largest of an arbitrary collection of types. We can apply the recursive metafunction formula which should by now be familiar:

+ +
+

Example 1. 'largest' metafunction

+ +
+// choose the larger of two types
+template<
+      typename T1
+    , typename T2
+    , bool choose1 = (sizeof(T1) > sizeof(T2)) // hands off!
+    >
+struct choose_larger
+{
+    typedef T1 type;
+};
+
+// specialization for the case where sizeof(T2) >= sizeof(T1)
+template< typename T1, typename T2 >
+struct choose_larger< T1,T2,false >
+{
+    typedef T2 type;
+};
+
+// get the largest of a cons-list
+template< typename T > struct largest;
+
+// specialization to peel apart the cons list
+template< typename First, typename Rest >
+struct largest< cons<First,Rest> >
+    : choose_larger< First, typename largest<Rest>::type >
+{
+    // type inherited from base
+};
+
+// specialization for loop termination
+template< typename First >
+struct largest< cons<First,nil> >
+{
+    typedef First type;
+};
+
+int main()
+{
+    // print the name of the largest of my_types
+    std::cout
+        << typeid(largest<my_types>::type).name()
+        << std::endl
+        ;
+}
+
+
+ +

There are several things worth noticing about this code:

+ +
+
    +
  • +

    It uses a few ad-hoc, esoteric techniques, or “hacks”. The default template argument choose1 (labeled “hands off!”) is one example. Without it, we would have needed yet another template to provide the implementation of choose_larger, or we would have had to provide the computation explicitly as a parameter to the template - perhaps not bad for this example, but it would make choose_larger much less useful and more error-prone. The other hack is the derivation of a specialization of largest from choose_larger. This is a code-saving device which allows the programmer to avoid writing “typedef typename ...::type type” in the template body.

    +
  • + +
  • +

    Even this simple metaprogram uses three separate partial specializations. The largest metafunction uses two specializations. One might expect that this indicates there are two termination conditions, but there are not: one specialization is needed simply to deal with access to the sequence elements. These specializations make the code difficult to read by spreading the definition of a single metafunction over several C++ template definitions. Also, because they are partial specializations, they make the code unusable for a large community of C++ programmers whose compilers don't support that feature.

    +
  • +
+
+ +

While these techniques are, of course, a valuable part of the arsenal of any good C++ metaprogrammer, their use tends to make programs written in what is already an unusual style harder-to-read and harder-to-write. By encapsulating commonly-used structures and dealing with loop terminations internally, the MPL reduces the need for both tricky hacks and for template specializations.

+
+
+ +
+
+
+

1.3. Why metaprogramming?

+
+
+ +

It's worth asking why anyone would want to do this. After all, even a simple toy example like the factorial metafunction is somewhat esoteric. To show how the type computation can be put to work, let's examine a simple example. The following code produces an array containing all possible permutations of another array:

+ +
+// can't return an array in C++, so we need this wrapper
+template< typename T >
+struct wrapper
+{
+    T x;
+};
+
+// return an array of the N! permutations of 'in'
+template< typename T >
+wrapper< typename permutation_holder<T>::type >
+all_permutations(T const& in)
+{
+    wrapper<typename permutation_holder<T>::type> result;
+
+    // copy the unpermutated array to the first result element
+    unsigned const N = sizeof(T) / sizeof(**result.x);
+    std::copy(&*in, &*in + N, result.x[0]);
+
+    // enumerate the permutations
+    unsigned const result_size = sizeof(result.x) / sizeof(T);
+    for (T* dst = result.x + 1; dst != result.x + result_size; ++dst)
+    {
+        T* src = dst - 1;
+        std::copy(*src, *src + N, *dst);
+        std::next_permutation(*dst, *dst + N);
+    }
+    return result;
+}
+
+ +

The runtime definition of factorial would be useless in all_permutations above, since in C++ the sizes of array members must be computed at compile-time. However, there are alternative approaches; how could we avoid metaprogramming, and what would the consequences be?

+ +
+
    +
  1. +

    We could write programs to interpret the metadata directly. In our factorial example, the array size could have been a runtime quantity; then we'd have been able to use the straightforward factorial function. However, that would imply the use of dynamic allocation, which is often expensive.

    + +

    To carry this further, YACC might be rewritten to accept a pointer-to-function returning tokens from the stream to be parsed, and a string containing the grammar description. This approach, however, would impose unacceptable runtime costs for most applications: either the parser would have to treat the grammar nondeterministically, exploring the grammar for each parse, or it would have to begin by replicating at runtime the substantial table-generation and optimization work of the existing YACC for each input grammar.

    +
  2. + +
  3. +

    We could replace the compile-time computation with our own analysis. After all, the size of arrays passed to all_permutations are always known at compile-time, and thus can be known to its user. We could ask the user to supply the result type explicitly:

    + +
    +template< typename Result, typename T >
    +Result all_permutations(T const& input);
    +
    + +

    The costs to this approach are obvious: we give up expressivity (by requiring the user to explicitly specify implementation details), and correctness (by allowing the user to specify them incorrectly). Anyone who has had to write parser tables by hand will tell you that the impracticality of this approach is the very reason of YACC's existence.

    + +

    In a language such as C++, where the metadata can be expressed in the same language as the rest of the user's program, expressivity is further enhanced: the user can invoke metaprograms directly, without learning a foreign syntax or interrupting the flow of her code.

    +
  4. +
+
+ +

So, the motivation for metaprogramming comes down to the combination of three factors: efficiency, expressivity, and correctness. While in classical programming there is always a tension between expressivity and correctness on one hand and efficiency on the other, in the metaprogramming world we wield new power: we can move the computation required for expressivity from runtime to compile-time.

+
+ +
+
+
+

1.4. Why a metaprogramming library?

+
+
+ +

One might just as well ask why we need any generic library:

+ +
+
    +
  • +

    Quality. Code that is appropriate for a general-purpose library is usually incidental to the purpose of its users. To a library developer, it is the central mission. On average, the containers and algorithms provided by any given C++ standard library implementation are more-flexible and better-implemented than the project-specific implementations which abound, because library development was treated as an end in itself rather than a task incidental to the development of some other application. With a centralized implementation for any given function, optimizations and improvements are more likely to have been applied.

    +
  • + +
  • +

    Re-use. More important even than the re-use of code which all libraries provide, a well-designed generic library establishes a framework of concepts and idioms which establishes a reusable mental model for approaching problems. Just as the C++ Standard Template Library gave us iterator concepts and a function object protocol, the Boost Metaprogramming Library provides type-iterators and metafunction class protocol. A well-considered framework of idioms saves the metaprogrammer from considering irrelevant implementation details and allows her to concentrate on the problem at hand.

    +
  • + +
  • +

    Portability. A good library can smooth over the ugly realities of platform differences. While in theory a metaprogramming library is fully generic and shouldn't be concerned with these issues, in practice support for templates remains inconsistent even four years after standardization. This should perhaps not be surprising: C++ templates are the language's furthest-reaching and most complicated feature, which largely accounts for the power of metaprogramming in C++.

    +
  • + +
  • +

    Fun. Repeating the same idioms over and over is tedious. It makes programmers tired and reduces productivity. Furthermore, when programmers get bored they get sloppy, and buggy code is even more costly than slowly-written code. Often the most useful libraries are simply patterns that have been “plucked” by an astute programmer from a sea of repetition. The MPL helps to reduce boredom by eliminating the need for the most commonly-repeated boilerplate coding patterns.

    +
  • +
+
+ +

As one can see, the MPL's development is motivated primarily by the same practical, real-world considerations that justify the development of any other library. Perhaps this is an indication that template metaprogramming is finally ready to leave the realm of the esoteric and enter the lingua franca of every day programmers.

+
+
+ +
+
+
+

2. Basic usage

+
+
+ +
+
+
+

2.1. Conditional type selection

+
+
+ +

Conditional type selection is the simplest basic construct of C++ template metaprogramming. Veldhuizen [Vel95a] was the first to show how to implement it, and Czarnecki and Eisenecker [CE00] first presented it as a standalone library primitive. The MPL defines the corresponding facility as follows:

+ +
+template<
+      typename Condition
+    , typename T1
+    , typename T2
+    >
+struct if_
+{
+    typedef /*unspecified*/ type;
+};
+
+ +

Note that the first template parameter of the template is a type.

+ +
+// usage/semantics
+typedef mpl::if_<mpl::true_c,char,long>::type t1;
+typedef mpl::if_<mpl::false_c,char,long>::type t2;
+
+BOOST_MPL_ASSERT_IS_SAME(t1, char);
+BOOST_MPL_ASSERT_IS_SAME(t2, long);
+
+ +

The construct is important because template metaprograms often contain a lot of decision-making code, and, as we will show, spelling it manually every time via (partial) class template specialization quickly becomes impractical. The template is also important from the point of encapsulating the compiler workarounds.

+ +
+
+
+

2.1.1. Delayed evaluation

+
+
+ +

The way the C++ template instantiation mechanism works imposes some subtle limitations on applicability of the type selection primitive (if_), compared to a manually implemented equivalent of the selection code. For example, suppose we are implementing a pointed_type traits template such that pointed_type<T>::type instantiated for a T that is either a plain pointer (U*), std::auto_ptr<U>, or any of the Boost smart pointers [SPL], e.g. boost::scoped_ptr<U>, will give us the pointed type (U):

+ +
+BOOST_MPL_ASSERT_IS_SAME(pointed_type<my*>::type, my);
+BOOST_MPL_ASSERT_IS_SAME(pointed_type< std::auto_ptr<my> >::type, my);
+BOOST_MPL_ASSERT_IS_SAME(pointed_type< boost::scoped_ptr<my> >::type, my);
+
+ +

Unfortunately, the straightforward application of if_ to this problem does not work: 1

+ +
+template< typename T >
+struct pointed_type
+    : mpl::if_<
+          boost::is_pointer<T>
+        , typename boost::remove_pointer<T>::type
+        , typename T::element_type // #1
+        >
+{
+};
+
+// the following code causes compilation error in line #1:
+// name followed by "::" must be a class or namespace name
+typedef pointed_type<char*>::type result;
+
+ +

Clearly, the expression typename T::element_type is not valid in the case of T == char*, and that's what the compiler is complaining about. Implementing the selection code manually solves the problem:

+ +
+namespace aux {
+// general case
+template< typename T, bool is_pointer = false >
+struct select_pointed_type
+{
+    typedef typename T::element_type type;
+};
+
+// specialization for plain pointers
+template< typename  T >
+struct select_pointed_type<T,true>
+{
+    typedef typename boost::remove_pointer<T>::type type;
+};
+}
+
+template< typename T >
+struct pointed_type
+   : aux::select_pointed_type<
+          T, boost::is_pointer<T>::value
+        >
+{
+};
+
+ +

But this quickly becomes awkward if needs to be done repeatedly, and this awkwardness is compounded when partial specialization is not available. We can try to work around the problem as follows:

+ +
+namespace aux {
+template< typename T >
+struct element_type
+{
+     typedef typename T::element_type type;
+};
+}
+
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , typename boost::remove_pointer<T>::type
+        , typename aux::element_type<T>::type
+        >::type type;
+};
+
+ +

but this doesn't work either - the access to the aux::element_type<T>'s nested type member still forces the compiler to instantiate element_type<T> with T == char*, and that instantiation is, of course, invalid. Also, although in our case this does not lead to a compile error, the boost::remove_pointer<T> template always gets instantiated as well, and for the same reason (because we are accessing its nested type member). Unnecessary instantiation that is not fatal may or may be not a problem, depending on the “weight” of the template (how much the instantiation taxes the compiler), but a general rule of thumb would be to avoid such code.

+ +

Returning to our error, to make the above code compile, we need to factor the act of “asking” aux::element_type<T> for its nested type out of the if_ invocation. The fact that both the boost::remove_pointer<T> trait template and aux::element_type<T> use the same naming convention for their result types makes the refactoring easier:

+ +
+template< typename T >
+struct pointed_type
+{
+ private:
+    typedef typename mpl::if_<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type func_;
+
+ public:
+    typedef typename func_::type type;
+};
+
+ +

Now the compiler is guaranteed not to instantiate both boost::remove_pointer<T> and aux::element_type<T>, even although they are used as actual parameters to the if_ template, so we are allowed to get away with aux::element_type<char*> so long as it won't end up being selected as func_.

+ +

The above technique is so common in template metaprograms, that it even makes sense to facilitate the selection of a nested type member by introducing a high-level equivalent to if_ - the one that will do the func_::type operation (that is called [nullary] metafunction class application) as a part of its invocation. The MPL provides such template - it's called apply_if. Using it, we can re-write the above code as simple as:

+ +
+template< typename T >
+struct pointed_type
+{
+    typedef typename mpl::apply_if<
+          boost::is_pointer<T>
+        , boost::remove_pointer<T>
+        , aux::element_type<T>
+        >::type type;
+};
+
+ +

To make our techniques review complete, let's consider a slightly different example - suppose we want to define a high-level wrapper around boost::remove_pointer traits template [TTL], which will strip the pointer qualification conditionally. We will call it remove_pointer_if:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::if_<
+          Condition
+        , typename boost::remove_pointer<T>::type
+        , T
+        >::type type;
+};
+
+ +

Now the above works the first time, but it suffers from the problem we mentioned earlier - boost::remove_pointer<T> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource [Abr01], and it is wasted by unnecessary template instantiations. We've just seen how to deal with the problem when both arguments to if_ are the results of nullary metafunction class applications, but in this example one of the arguments (T) is just a simple type, so the refactoring just doesn't seem possible.

+ +

The easiest way out of this situation would be to pass to if_ a real nullary metafunction instead of T - the one that returns T on its invocation. The MPL provides a simple way to do it - we just substitute identity<T> and apply_if for T and if_:

+ +
+template<
+      typename Condition
+    , typename T
+    >
+struct remove_pointer_if
+{
+    typedef typename mpl::apply_if<
+          Condition
+        , boost::remove_pointer<T>
+        , mpl::identity<T>
+        >::type type;
+};
+
+ +

which gives us exactly what we wanted.

+
+
+ +
+
+
+

2.2. Metafunctions

+
+
+ +
+
+
+

2.2.1. The simple form

+
+
+ +

In C++, the basic underlying language construct which allows parameterized compile-time computation is the class template ([ISO98], section 14.5.1 [temp.class]). A bare class template is the simplest possible model we could choose for metafunctions: it can take types and/or non-type arguments as actual template parameters, and instantiation “returns” a new type. For example, the following produces a type derived from its arguments:

+ +
+template< typename T1, typename T2 >
+struct derive : T1, T2
+{
+};
+
+ +

However, this model is far too limiting: it restricts the metafunction result not only to class types, but to instantiations of a given class template, to say nothing of the fact that every metafunction invocation introduces an additional level of template nesting. While that might be acceptable for this particular metafunction, any model which prevented us from “returning”, say, int is obviously not general enough. To meet this basic requirement, we must rely on a nested type to provide our return value:

+ +
+template< typename T1, typename T2 >
+struct derive
+{
+    struct type : N1, N2 {};
+};
+
+// silly specialization, but demonstrates "returning" int
+template<>
+struct derive<void,void>
+{
+    typedef int type;
+};
+
+ +

Veldhuizen [Vel95a] was first to talk about class templates of this form as “compile-time functions”, and Czarnecki and Eisenecker [CE00] have introduced “template metafunction” as an equivalent term (they also use the simpler term “metafunction”, as do we). Czarnecki and Eisenecker have also recognized the limitations of the simple metafunction representation and suggested the form that we discuss in Section 2.2.3.

+
+ +
+
+
+

2.2.2. Higher-order metafunctions

+
+
+ +

While syntactically simple, the simple template metafunction form does not always interact optimally with the rest of C++. In particular, the simple metafunction form makes it unnecessarily awkward and tedious to define and work with higher-order metafunctions (metafunctions that operate on other metafunctions). In order to pass a simple metafunction to another template, we need to use template template parameters:

+ +
+// returns F(T1,F(T2,T3))
+template<
+      template<typename> class F
+    , typename T1
+    , typename T2
+    , typename T3
+    >
+struct apply_twice
+{
+  typedef typename F<
+        T1
+      , typename F<T2,T3>::type
+      >::type type;
+};
+
+// a new metafunction returning a type derived from T1, T2, and T3
+template<
+      typename T1
+    , typename T2
+    , typename T3
+    >
+struct derive3
+    : apply_twice<derive,T1,T2,T3>
+{
+};
+
+ +

This looks different, but it seems to work. 2 However, things begin to break down noticeably when we want to “return” a metafunction from our metafunction:

+ +
+// returns G s.t. G(T1,T2,T3) == F(T1,F(T2,T3))
+template< template<typename> class F >
+struct compose_self
+{
+    template<
+          typename T1
+        , typename T2
+        , typename T3
+        > 
+    struct type
+        : apply_twice<F,T1,T2,T3>
+    {
+    };
+};
+
+ +

The first and most obvious problem is that the result of applying compose_self is not itself a type, but a template, so it can't be passed in the usual ways to other metafunctions. A more subtle issue, however, is that the metafunction “returned” is not exactly what we intended. Although it acts just like apply_twice, it differs in one important respect: its identity. In the C++ type system, compose_self<F>::template type<T,U,V> is not a synonym for apply_twice<F,T,U,V>, and any metaprogram which compared metafunctions would discover that fact.

+ +

Because C++ makes a strict distinction between type and class template template parameters, reliance on simple metafunctions creates a “wall” between metafunctions and metadata, relegating metafunctions to the status of second-class citizens. For example, recalling our introduction to type sequences, there's no way to make a cons list of metafunctions:

+ +
+typedef cons<derive, cons<derive3, nil> > derive_functions; // error!
+
+ +

We might consider redefining our cons cell so we can pass derive as the head element:

+ +
+template <
+      template< template<typename T, typename U> class F
+    , typename Tail
+    >
+struct cons;
+
+ +

However, now we have another problem: C++ templates are polymorphic with respect to their type arguments, but not with respect to template template parameters. The arity (number of parameters) of any template template parameter is strictly enforced, so we still can't embed derive3 in a cons list. Moreover, polymorphism between types and metafunctions is not supported (the compiler expects one or the other), and as we've seen, the syntax and semantics of “returned” metafunctions is different from that of returned types. Trying to accomplish everything with the simple template metafunction form would seriously limit the applicability of higher-order metafunctions and would have an overall negative effect on the both conceptual and implementation clarity, simplicity and size of the library.

+
+ +
+
+
+

2.2.3. Metafunction classes

+
+
+ +

Fortunately, the truism that “there is no problem in software which can't be solved by adding yet another level of indirection” applies here. To elevate metafunctions to the status of first-class objects, the MPL introduces the concept of a “metafunction class”:

+ +
+// metafunction class form of derive
+struct derive
+{
+    template< typename N1, typename N2 >
+    struct apply
+    {
+        struct type : N1, N2 {};
+    };
+};
+
+ +

This form should look familiar to anyone acquainted with function objects in STL, with the nested apply template taking the same role as the runtime function-call operator. In fact, compile-time metafunction classes have the same relationship to metafunctions that runtime function objects have to functions:

+ +
+// function form of add
+template< typename T > T add(T x, T y) { return x + y; }
+
+// function object form of add
+struct add
+{
+    template< typename T >
+    T operator()(T x, T y) { return x + y; }
+};
+
+
+ +
+
+
+

2.2.4. One size fits all?

+
+
+ +

The metafunction class form solves all the problems with ordinary template metafunction mentioned earlier: since it is a regular class, it can be placed in compile-time metadata sequences and manipulated by other metafunctions using the same protocols as for any other metadata. We thereby avoid the code-duplication needed to provide versions of each library component to operate on ordinary metadata and on metafunctions with each distinct supported arity.

+ +

On the other hand, it seems that accepting metafunction classes as the representation for compile-time function entities imposes code duplication danger as well: if the library's own primitives, algorithms, etc. are represented as class templates, that means that one either cannot reuse these algorithms in the context of higher-order functions, or she have to duplicate all algorithms in the second form, so, for instance, there would be two versions of find:

+ +
+// user-friendly form
+template<
+      typename Sequence
+    , typename T
+    >
+struct find
+{
+    typedef /* ... */ type;
+};
+
+// "metafunction class" form
+struct find_func
+{
+    template< typename Sequence, typename T >
+    struct apply
+    {
+        typedef /* ... */ type;
+    };
+};
+
+ +

Of course, the third option is to eliminate “user-friendly form” completely so one would always have to write:

+ +
+typedef mpl::find::apply<list,long>::type iter;
+// or, if one prefers,
+// typedef mpl::apply< mpl::find,list,long >::type iter;
+
+ +

instead of

+ +
+typedef mpl::find<list,long>::type iter;
+
+ +

That too would hurt usability, considering that the direct invocations of library's algorithms are far more often-used than passing algorithms as arguments to other algorithms/metafunctions.

+
+ +
+
+
+

2.2.5. From metafunction to metafunction class

+
+
+ +

The MPL's answer to this dilemma is lambda expressions. Lambda is the mechanism that enables the library to curry metafunctions and convert them into metafunction classes, so when one wants to pass the find algorithm as an argument to a higher-order metafunction, she just write:

+ +
+using namespace mpl::placeholder;
+typedef mpl::apply< my_f, mpl::find<_1,_2> >::type result;
+
+ +

where _1 and _2 are placeholders for the first and second arguments to the resulting metafunction class. This preserves the intuitive syntax below for when the user wants to use find directly in her code:

+ +
+typedef mpl::find<list,long>::type iter;
+
+ +

Lambda facility is described in more details in Section 3.

+
+
+ +
+
+
+

2.3. Sequences, algorithms, and iterators

+
+
+ +
+
+
+

2.3.1. Introduction

+
+
+ +

Compile-time iteration over a sequence (of types) is one of the basic concepts of template metaprogramming. Differences in types of objects being manipulated is the most common point of variability of similar but not identical code/design, and such designs are the direct target for some metaprogramming. Templates were originally designed to solve this exact problem (e.g. std::vector). However, without predefined abstractions/constructs for manipulating/iterating over sequences of types (as opposed to standalone types), and without known techniques for emulating these constructs using the current language facilities, their effect on helping high-level metaprogramming happen has been limited.

+ +

Czarnecki and Eisenecker [CE98], [CE00] were the first to introduce compile-time sequences of types and some simple algorithms on them, although the idea of representing common data structures like trees, lists, etc. at compile time, using class template composition has been around for a while (e.g. most of the expression template libraries build such trees as a part of their expression "parsing" process [Vel95b]). Alexandrescu [Ale01] used lists of types and some algorithms on them to implement several design patterns; the accompanying code is known as the Loki library [Loki].

+
+ +
+
+
+

2.3.2. Algorithms and sequences

+
+
+ +

Most of the algorithms in the Boost Metaprogramming Library operate on sequences. For example, searching for a type in a list looks like this:

+ +
+typedef mpl::list<char,short,int,long,float,double> types;
+typedef mpl::find<types,long>::type iter;
+
+ +

Here, find accepts two parameters - a sequence to search (types) and the type to search for (long) - and returns an iterator iter pointing to the first element of the sequence such that iter::type is identical to long. If no such element exists, iter is identical to end<types>::type. Basically, this is how one would search for a value in a std::list or std::vector, except that mpl::find accepts the sequence as a single parameter, while std::find takes two iterators. Everything else is pretty much the same - the names are the same, the semantics are very close, there are iterators, and one can search not only by type, but also by using a predicate:

+ +
+typedef mpl::find_if< types,boost::is_float<_> >::type iter;
+
+ +

This conceptual/syntactical similarity with the STL is not coincidental. Reusing the conceptual framework of the STL in the compile-time world allows us to apply familiar and sound approaches for dealing with sequential data structures. The algorithms and idioms which programmers already know from the STL can be applied again at compile-time. We consider this to be one of MPL's greatest strengths, distinguishing it from earlier attempts to build a template metaprogramming library.

+
+ +
+
+
+

2.3.3. Sequence concepts

+
+
+ +

In the find example above, we searched for the type in a sequence built using the mpl::list template; but list is not the only sequence that the library provides. Neither is mpl::find or any other algorithm hard-coded to work only with list sequences. list is just one model of MPL's Forward Sequence concept, and find works with anything that satisfies this concept's requirements. The hierarchy of sequence concepts in MPL is quite simple - a Sequence is any compile-time entity for which begin<> and end<> produce iterators to the range of its elements; a Forward Sequence is a Sequence whose iterators satisfy Forward Iterator requirements; a Bidirectional Sequence is a Forward Sequence whose iterators satisfy Bidirectional Iterator requirements; finally, a Random Access Sequence is a Bidirectional Sequence whose iterators satisfy Random Access Iterator requirements. 3

+ +

Decoupling algorithms from particular sequence implementations (through iterators) allows a metaprogrammer to create her own sequence types and to retain the rest of the library at her disposal. For example, one can define a tiny_list for dealing with sequences of three types as follows:

+ +
+template< typename TinyList, long Pos >
+struct tiny_list_item;
+
+template< typename TinyList, long Pos >
+struct tiny_list_iterator
+{
+    typedef typename tiny_list_item<TinyList,Pos>::type type;
+    typedef tiny_list_iterator<TinyList, Pos-1> prior;
+    typedef tiny_list_iterator<TinyList, Pos+1> next;
+};
+
+template< typename T0, typename T1, typename T2 >
+struct tiny_list
+{
+    typedef tiny_list_iterator<tiny_list, 0> begin;
+    typedef tiny_list_iterator<tiny_list, 3> end;
+    typedef T0 type0;
+    typedef T1 type1;
+    typedef T2 type2;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,0>
+{
+    typedef typename TinyList::type0 type;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,1>
+{
+    typedef typename TinyList::type1 type;
+};
+
+template< typename TinyList >
+struct tiny_list_item<TinyList,2>
+{
+    typedef typename TinyList::type2 type;
+};
+
+ +

and then use it with any of the library algorithms as if it were mpl::list:

+ +
+typedef tiny_list< char,short,int > types;
+typedef mpl::transform<
+      types
+    , boost::add_pointer<_1>
+    >::type pointers;
+
+ +

Note that tiny_list is a model of Bidirectional Sequence; it would be a Random Access Sequence if we added advance and distance members to tiny_list_iterator:

+ +
+template< typename TinyList, long Pos >
+struct tiny_list_iterator
+{
+    static long const position = Pos;
+
+    typedef typename tiny_list_item<TinyList,Pos>::type type;
+    typedef tiny_list_iterator<TinyList, Pos-1> prior;
+    typedef tiny_list_iterator<TinyList, Pos+1> next;
+
+    template< typename N > struct advance
+    {
+        typedef tiny_list_iterator<
+              TinyList
+            , Pos + N::value
+            > type;
+    };
+
+    template< typename Other > struct distance
+    {
+        typedef mpl::integral_c<
+              long
+            , Other::position - position
+            > type;
+    };
+};
+
+ +

While the tiny_list itself might be not that interesting (after all, it can hold only three elements), if the technique above could be automated so we would be able to define not-so-tiny sequences (with five, ten, twenty, etc. elements), it would be very valuable. 4

+ +

External code generation is an option, but there exists a solution within the language. However, it is not a template metaprogramming, but rather preprocessor metaprogramming. In fact, MPL's vector - a fixed-size type sequence that provides random-access iterators - is implemented very much like the above tiny_list - using the Boost Preprocessor library [PRE].

+
+ +
+
+
+

2.3.4. Ad hoc example revisited

+
+
+ +

So, the library provides its users with almost complete compile-time equivalent of the STL framework. Does it help them to solve their metaprogramming tasks? Let's return to our earlier largest example to see if we can rewrite it in a better way with what MPL has to offer. Well, actually, there is not much to look at, because the MPL implementation is a one-liner (we'll spread it out here for readability) 5 :

+ +
+template< typename Sequence >
+struct largest
+{
+    typedef typename mpl::max_element<
+          Sequence
+          mpl::less<
+              mpl::size_of<_1>
+            , mpl::size_of<_2>
+            >
+        >::type iter;
+
+    typedef typename iter::type type;
+};
+
+ +

There are no more termination conditions with tricky pattern matching, no more partial specializations; and even more importantly, it's obvious what the above code does - even although it's all templates - something that one could not say about the original version.

+
+ +
+
+
+

2.3.5. iter_fold as the main iteration algorithm

+
+
+ +

For the purpose of examining a little bit more of the library's internal structure, let's look at how max_element from the above example is implemented. One might expect that now we will again see all these awkward partial specializations, esoteric pattern matching, etc. Well, let's see:

+ +
+template<
+      typename Sequence
+    , typename Predicate
+    >
+struct max_element
+{
+    typedef typename mpl::iter_fold<    
+          Sequence
+        , typename mpl::begin<Sequence>::type
+        , if_< less< deref<_1>,deref<_2> >, _2, _1 >
+        >::type type;
+};
+
+ +

The first thing to notice here is that this algorithm is implemented in terms of another one: iter_fold. In fact, this is probably the most important point of the example, because nearly all other generic sequence algorithms in the library are implemented in terms of iter_fold. If a user should ever need to implement her own sequence algorithm, she'll almost certainly be able to do so using this primitive, which means she won't have to resort to implementing hand-crafted iteration, pattern matching of special cases for loop termination, or workarounds for lack of partial specialization. It also means that her algorithm will automatically benefit from any optimizations the library has implemented, (e.g. recursion unrolling), and that it will work with any sequence that is a model of ForwardSequence, because iter_fold does not require anything more of its sequence argument.

+ +

iter_fold algorithm is basically a compile-time equivalent of the fold or reduce functions that comprise the basic and well-known primitives of many functional programming languages. An analogy more familiar to a C++ programmer would be the std::accumulate algorithm from the C++ standard library ([ISO98], section 26.4.1 [lib.accumulate]). However, iter_fold is designed to take advantage of the natural characteristics of recursive traversal: it accepts two metafunction class arguments, the first of which is applied to the state "on the way in" and the second of which is applied "on the way out".

+ +

The interface to iter_fold is defined in MPL as follows:

+ +
+template<
+      typename Sequence
+    , typename InitialState
+    , typename ForwardOp
+    , typename BackwardOp = _1
+    >
+struct iter_fold
+{
+    typedef /*unspecified*/ type;
+};
+
+ +

The algorithm “returns” the result of two-way successive applications of binary ForwardOp and BackwardOp operations to iterators in range [begin<Sequence>::type, end<Sequence>::type) and previous result of an operation; the InitialState is logically placed before the sequence and included in the forward traversal. The result type is identical to InitialState if the sequence is empty.

+ +

The library also provides iter_fold_backward, fold, and fold_backward algorithms which wrap iter_fold to accommodate its most common usage patterns.

+
+ +
+
+
+

2.3.6. Sequences of numbers

+
+
+ +

What we've seen so far were sequences (and algorithms on sequences) of types. It is both possible and easy to manipulate compile-time values using the library as well. The only thing to remember is that in C++, class template non-type template parameters give us one more example of non-polymorphic behavior. In other words, if one declared a metafunction to take a non-type template parameter (e.g. long) it's not possible to pass anything besides compile-time integral constants to it:

+ +
+template< long N1, long N2 >
+struct equal_to
+{
+    static bool const value = (N1 == N2);
+};
+
+equal_to<5,5>::value; // ok
+equal_to<int,int>::value; // error!
+
+ +

And of course this doesn't work the other way around either:

+ +
+typedef mpl::list<1,2,3,4,5> numbers; // error!
+
+ +

While this may be an obvious limitation, it imposes yet another dilemma on the library design: on the one hand, we don't want to restrict users to type manipulations only, and on the other hand, full support for integral manipulations would require at least duplication of most of the library facilities 6 - the same situation as we would have if we had chosen to represent metafunctions as ordinary class templates. The solution for this issue is the same as well: we represent integral values by wrapping them in types 7 . For example, to create a list of numbers one can write:

+ +
+typedef mpl::list<
+      mpl::int_c<1>
+    , mpl::int_c<2>
+    , mpl::int_c<3>
+    , mpl::int_c<4>
+    , mpl::int_c<5>
+    > numbers;
+
+ +

Wrapping integral constants into types to make them first-class citizens is important well inside metaprograms, where one often doesn't know (and doesn't care) if the metafunctions she is using operate on types, integral values, other metafunctions, or something else, like fixed-point or rational numbers (mpl::fixed_c and mpl::rational_c).

+ +

But, from the user's perspective, the above example is much more verbose than the shorter, incorrect one. Thus, for the purpose of convenience, the library does provide users with a template that takes non-type template parameters, but offers a more compact notation:

+ +
+typedef mpl::list_c<long,1,2,3,4,5> numbers;
+
+ +

There is a similar vector counterpart as well:

+ +
+typedef mpl::vector_c<long,1,2,3,4,5> numbers;
+
+
+ +
+
+
+

2.3.7. A variety of sequences

+
+
+ +

Previous efforts to provide generalized metaprogramming facilities for C++ have always concentrated on cons-style type lists and a few core algorithms like size and at, which are tied to the specific sequence implementation. Such systems have an elegant simplicity reminiscent of the analogous functionality in pure functional Lisp. It is much more time-consuming to implement even a basic set of the sequence algorithms provided by equivalent run-time libraries (the STL in particular), but if we have learned anything from the STL, it is that tying those algorithms' implementations to a specific sequence implementation is a misguided effort!

+ +

The truth is that there is no single “best” type sequence implementation for the same reasons that there will never be a single “best” runtime sequence implementation. Furthermore, there are already quite a number of type list implementations in use today; and just as the STL algorithms can operate on sequences which don't come from STL containers, so the MPL algorithms are designed to work with foreign type sequences.

+ +

It may be an eye-opening fact for some that type lists are not the only useful compile-time sequence. Again, the need for a variety of compile-time containers arises for the same reasons that we have lists, vectors, deques, and sets in the C++ standard library - different containers have different functional and performance characteristics which determine not only applicability and efficiency of particular algorithms, but also the expressiveness or verbosity of the code that uses them. While runtime performance is not an issue for C++ metaprograms, compilation speed is often a significant bottleneck to advanced C++ software development [Abr01].

+ +

The MPL provides five built-in sequences: list, list_c (really just a list of value wrappers), vector, a randomly-accessible sequence of fixed maximum size, vector_c, and range_c, a randomly-accessible sequence of consecutive integral values. More important, however, is its ability to adapt to arbitrary sequence types. The only core operations that a sequence is required to provide in order to be used with the library algorithms are begin<> and end<> metafunctions which "return" iterators into the sequence. As with the STL, it is the iterators which are used to implement most of the general-purpose sequence algorithms the library provides. Also, as with the STL, algorithm specialization is used to take advantage of implementation knowledge about particular sequences: many of the "basic" sequence operations such as back<>, front<>, size<>, and at<> are specialized on sequence type to provide a more efficient implementation than the fully generic version.

+
+ +
+
+
+

2.3.8. Loop/recursion unrolling

+
+
+ +

Almost coincidentally, loop unrolling can be as important to compile-time iterative algorithms as it is to runtime algorithms. To see why, one must first remember that all "loops" in C++ metaprograms, are in fact, implemented with recursion, and that the template instantiation depth can be a valuable resource in a compiler implementation. In fact, Annex B of the C++ standard ([ISO98], annex B [limits]) recommends a minimum depth of 17 recursively nested template instantiations; but this is far too low for many serious metaprograms, some of which easily exceed the hard-coded instantiation limits of some otherwise excellent compilers. To see how this works in action, let's examine a straightforward implementation of the fold metafunction, which combines some algorithm state with each element of a sequence:

+ +
+namespace aux {
+
+// unspecialized version combines the initial state and first element
+// and recurses to process the rest
+template<
+      typename Start
+    , typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl
+  : fold_impl<
+        typename Start::next
+      , Finish
+      , typename apply<
+              BinaryFunction
+            , State
+            , typename Start::type
+            >::type
+      , BinaryFunction
+      >
+{
+};
+
+// specialization for loop termination
+template<
+      typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl<Finish,Finish,State,BinaryFunction>
+{
+    typedef State type;
+};
+
+} // namespace aux
+
+// public interface
+template<
+      typename Sequence
+    , typename State
+    , typename ForwardOp
+    >
+struct fold
+    : aux::fold_impl<
+        , typename begin<Sequence>::type
+        , typename end<Sequence>::type
+        , State
+        , typename lambda<ForwardOp>::type
+        >
+{
+};
+
+ +

Although simple and elegant, this implementation will always incur at least as many levels of recursive template instantiation as there are elements in the input sequence. 8 The library addresses this problem by explicitly "unrolling" the recursion. To apply the technique to our fold example, we begin by factoring out a single step of the algorithm. Our fold_impl_step metafunction has two results: type (the next state), and iterator (the next sequence position).

+ +
+template<
+      typename BinaryFunction
+    , typename State
+    , typename Start
+    , typename Finish
+    >
+struct fold_impl_step
+{
+    typedef typename apply<
+          BinaryFunction
+        , State
+        , typename Start::type
+        >::type type;
+
+    typedef typename Start::next iterator;
+};
+
+ +

As with our main algorithm implementation, we specialize for the loop termination condition so that the step becomes a no-op:

+ +
+template<
+      typename BinaryFunction
+    , typename State
+    , typename Finish
+    >
+struct fold_impl_step<BinaryFunction,State,Finish,Finish>
+{
+    typedef State type;
+    typedef Finish iterator;
+};
+
+ +

Now we can now reduce fold's instantiation depth by any constant factor N simply by inserting N invocations of fold_impl_step. Here we've chosen a factor of 4:

+ +
+template<
+      typename Start
+    , typename Finish
+    , typename State
+    , typename BinaryFunction
+    >
+struct fold_impl
+{
+ private:
+    typedef fold_impl_step<
+        BinaryFunction
+      , State
+      , Start
+      , Finish
+      > next1;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next1::type
+      , typename next1::iterator
+      , Finish
+      > next2;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next2::type
+      , typename next2::iterator
+      , Finish
+      > next3;
+    
+    typedef fold_impl_step<
+        BinaryFunction
+      , typename next3::type
+      , typename next3::iterator
+      , Finish
+      > next4;
+    
+    typedef fold_impl_step<
+          typename next4::iterator
+        , Finish
+        , typename next4::type
+        , BinaryFunction
+        > recursion;
+
+ public:
+    typedef typename recursion::type type;
+};
+
+ +

The MPL applies this unrolling technique across all algorithms with an unrolling factor tuned according to the demands of the C++ implementation in use, and with an option for the user to override the value. 9 This fact enables users to push beyond the metaprogramming limits they would usually encounter with more naive algorithm implementations. Experiments also show a small (up to 10%) increase in metaprogram instantiation speed on some compilers when loop unrolling is used.

+
+
+
+ +
+
+
+

3. Lambda facility

+
+
+ +

The MPL's lambda facility allows the inline composition of class templates into “lambda expressions”, which are classes and can therefore be passed around as ordinary metafunction classes, or transformed into metafunction classes before application using the expression:

+ +
+typedef mpl::lambda<expr>::type func;
+
+ +

For example, boost::remove_const traits template from Boost type_traits library [TTL] is a class template (obviously), or a metafunction in MPL terminology. The simplest example of an “inline composition” of it would be something like:

+ +
+typedef boost::remove_const<_1> expr;
+
+ +

This forms a so called “lambda expression”, which is neither a metafunction class, nor a metafunction, yet can be passed around everywhere because it's an ordinary C++ class, because all MPL facilities are polymorphic with respect to their arguments. Now, that lambda expression can be transformed into a metafunction class using the MPL's lambda facility:

+ +
+typedef boost::remove_const<_1> expr;
+typedef mpl::lambda<expr>::type func;
+
+ +

The func is a unary metafunction class and can be used as such. In particular, it can be pass around or invoked (applied):

+ +
+typedef mpl::apply<func,int const>::type res;
+BOOST_MPL_ASSERT_IS_SAME(res, int);
+
+ +

or even

+ +
+typedef func::apply<int const>::type res;
+BOOST_MPL_ASSERT_IS_SAME(res, int);
+
+ +

Inline composition is very appealing syntactically when one deals with metafunctions, because it makes the expression obvious:

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_1>, mpl::int_c<16> >
+    , boost::is_same<_1,_2>
+    > expr;
+
+typedef mpl::lambda<expr>::type func;
+
+ +

And one does not have to specify the last part (typedef lambda<expr>::type func), because all the algorithms do this to any of their metafunction class operands internally (a lambda<T>::type expression applied to a metafunction class gives back the same metafunction class, so it's safe to apply the expression unconditionally).

+ +

The alternative way to write an equivalent of the above metafunction class would be:

+ +
+typedef bind<
+      mpl::meta_fun2<mpl::logical_or>
+    , mpl::bind< mpl::meta_fun2<mpl::less>
+        , mpl::bind< mpl::meta_fun1<mpl::size_of>,_1 >
+        , mpl::int_c<16>
+        >
+    , mpl::bind< mpl::meta_fun2<boost::is_same>,_1,_2 >
+    > func;
+
+ +

Or to use mpl::compose_ family of templates in a similar way. Here, we use mpl::meta_fun templates to convert metafunctions into metafunction classes and then combine them using mpl::bind. The transformation from this form to the above inline lambda expression and vice-versa is mechanical, and that is essentially what the typedef mpl::lambda<expr>::type expression does.

+ +

For its own metafunctions (algorithms, primitives, etc.), MPL enables one to write the above in a less cumbersome way:

+ +
+typedef mpl::bind<
+      mpl::logical_or<>
+    , mpl::bind< mpl::less<>, mpl::bind<mpl::size_of<>,_1>, mpl::int_c<16> >
+    , mpl::bind< mpl::make_f2<boost::is_same>, _1,_2 >
+    > func;
+
+ +

Note that we still have to wrap is_same into make_f2, because it's a foreign template.

+ +

Now, about combining class template metafunctions and metafunction classes in the single lambda expression - it can be done like this:

+ +
+struct my_predicate
+{
+    template< typename T1, typename T2 > struct apply
+    {
+        //...
+    };
+};
+
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , mpl::bind< my_predicate,_,_ > // here
+    > expr;
+
+ +

To bind something to one of its arguments (or change the order of parameters), then use either:

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , mpl::bind<my_predicate,int,_>::type // here
+    > expr;
+
+ +

or

+ +
+typedef mpl::logical_or<
+      mpl::less< mpl::size_of<_>,mpl::int_c<16> >
+    , my_predicate::apply<int,_> // here
+    > expr;
+
+
+ +
+
+
+

4. Code generation facilities

+
+
+ +

There are cases, especially in the domain of numeric computation, when one wants to perform some part of the calculations at compile-time, and then pass the results to a run-time part of the program for further processing. For example, suppose one has implemented a complex compile-time algorithm that works with fixed-point arithmetic:

+ +
+// fixed-point algorithm input
+typedef mpl::vector<
+      mpl::fixed_c<-1,2345678>
+    , mpl::fixed_c<9,0001>
+    // ..
+    , mpl::fixed_c<3,14159>
+    > input_data;
+
+/*
+  complex compile-time algorithm 
+*/
+typedef /*...*/ result_data;
+
+ +

Suppose the result_data here is a sequence of mpl::fixed_c types that keeps the results of the algorithm, and now one wishes to feed that result to the run-time part of the algorithm. With MPL she can do this:

+ +
+double my_algorithm()
+{
+    // passing the results to the run-time part of the program
+    std::vector<double> results;
+    results.reserve(mpl::size<result_data>::value);
+    mpl::for_each<numbers,_>(
+          boost::bind(&std::vector<double>::push_back, &results, _1)
+        );
+    // ...
+}
+
+ +

The for_each<numbers,_>(...) call is what actually transfers the compile-time result_data into run-time results. for_each is a function template declared as:

+ +
+template<
+      typename Seq
+    , typename TransformOp
+    , typename F
+    >
+void for_each(F f)
+{
+    // ...
+}
+
+ +

To call the function, one is required to explicitly provide two actual template parameters, a compile-time sequence Seq and a unary transformation metafunction TransformOp, plus a run-time function argument f (in our example, numbers, _, and boost::bind(...) correspondingly). f is a function object which operator() is called for every element in the Seq tranfromed by TransformOp.

+ +

Applying this to our example, the

+ +
+mpl::for_each<numbers,_>(
+      boost::bind(&std::vector<double>::push_back, &results, _1)
+    );
+
+ +

call is roughly equivalent to this:

+ +
+f(mpl::apply< _,mpl::at_c<result_data,0>::type >::type());
+f(mpl::apply< _,mpl::at_c<result_data,1>::type >::type());
+// ...
+f(mpl::apply< _,mpl::at_c<result_data,n>::type >::type());
+
+ +

where n == mpl::size<result_data>::type::value.

+
+ +
+
+
+

5. Example: a compile-time FSM generator

+
+
+ +

Finite state machines (FSMs) are an important tool for describing and implementing program behavior [HU79], [Mar98]. They also are a good example of a domain in which metaprogramming can be applied to reduce the amount of repetitive and boilerplate operations one must perform in order to implement these simple mathematical models in code. Below we present a simple state machine generator that has been implemented using Boost Metaprogramming Library facilities. The generator takes a compile-time automata description, and converts it into C++ code that implements the FSM at run-time.

+ +

The FSM description is basically a combination of states and events plus a state transition table (STT), which ties them all together. The generator walks through the table and generates the state machine's process_event method that is the essence of an FSM.

+ +

Suppose we want to implement a simple music player using a finite state machine model. The state transition table for the FSM is shown in Table 1. The STT format reflects the way one usually describes the behavior of an FSM in plain English. For example, the first line of the table can be read as follows: “If the model is in the stopped state and the play_event is received, then the do_play transition function is called, and the model transitions to the playing state”.

+ +
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StateEventNext stateTransition function
stoppedplay_eventplayingdo_play
playingstop_eventstoppeddo_stop
playingpause_eventpauseddo_pause
pausedplay_eventplayingdo_resume
pausedstop_eventstoppeddo_stop
+ +

Table 1. Player's state transition table with actions

+
+ +

The transition table provides us with a complete formal definition of the target FSM, and there are several ways to transform that definition into code. For instance, if we define states as members of an enumeration type, and events as classes derived from some base event class 10 , like so:

+ +
+class player
+{
+ public:
+    // event declarations
+    struct event;
+    struct play_event;
+    struct stop_event;
+    struct pause_event;
+
+    // "input" function
+    void process_event(event const&); // throws
+
+ private:
+    // states
+    enum state_t { stopped, playing, paused };
+
+    // transition functions
+    void do_play(play_event const&);
+    void do_stop(stop_event const&);
+    void do_pause(pause_event const&);
+    void do_resume(play_event const&);
+
+ private:
+    state_t m_state;
+};
+
+ +

then the most straightforward way to derive the FSM implementation from the above table would be something like this:

+ +
+void player::process_event(event const& e)
+{
+    if (m_state == stopped)
+    {
+        if (typeid(e) == typeid(play_event))
+        {
+            do_play(static_cast<play_event const&>(e));
+            m_state = playing;
+            return;
+        }
+    }
+    else if (m_state == playing)
+    {
+        if (typeid(e) == typeid(stop_event))
+        {
+            do_stop(static_cast<stop_event const&>(e));
+            m_state = stopped;
+            return;
+        }
+
+        if (typeid(e) == typeid(pause_event))
+        {
+            do_pause(static_cast<pause_event const&>(e));
+            m_state = paused;
+            return;
+        }
+    }
+    else if (m_state == paused)
+    {
+        if (typeid(e) == typeid(stop_event))
+        {
+            do_stop(static_cast<stop_event const&>(e));
+            m_state = stopped;
+            return;
+        }
+
+        if (typeid(e) == typeid(play_event))
+        {
+            do_play(static_cast<play_event const&>(e));
+            m_state = playing;
+            return;
+        }
+    }
+    else
+    {
+        throw logic_error(
+            boost::format("unknown state: %d")
+                % static_cast<int>(m_state)
+            );
+    }
+
+    throw std::logic_error(
+        "unexpected event: " + typeid(e).name()
+        );
+}
+
+ +

Although there is nothing particularly wrong with implementing an FSM's structure using nested if (or switch-case) statements, the obvious weakness of this approach is that most of the above code is boilerplate. What one tends to do with boilerplate code is to copy and paste it, then change names etc. to adjust it to its new location; and that's where the errors are most likely to creep in. Since all the lines of event processing look alike (structurally), it's very easy to overlook or forget something that needs to be changed, and many such errors won't appear until the runtime.

+ +

The transition table of our FSM is just five lines long; ideally, we would like the skeleton implementation of the automata's controlling logic to be equally short (or, at least, to look equally short, i.e. to be encapsulated in some form so we never worry about it).

+ +
+
+
+

5.1. Implementation

+
+
+ +

To represent the STT in a C++ program, we define a transition class template that represents a single line of the table. Then the table itself can be represented as a sequence of such lines:

+ +
+typedef mpl::list<
+      transition<stopped, play_event,  playing, &player::do_play>
+    , transition<playing, stop_event,  stopped, &player::do_stop>
+    , transition<playing, pause_event, paused,  &player::do_pause>
+    , transition<paused,  play_event,  playing, &player::do_resume>
+    , transition<paused,  stop_event,  stopped, &player::do_stop>
+    >::type transition_table;
+
+ +

Now, the complete FSM will look like this:

+ +
+class player
+    : state_machine<player>
+{
+ private:
+    typedef player self_t;
+
+    // state invariants
+    void stopped_state_invariant();
+    void playing_state_invariant();
+    void paused_state_invariant();
+
+    // states (invariants are passed as non-type template arguments,
+    // and are called then the FSM enters the corresponding state)
+    typedef state<0, &self_t::stopped_state_invariant> stopped;
+    typedef state<1, &self_t::playing_state_invariant> playing;
+    typedef state<2, &self_t::paused_state_invariant> paused;
+
+ private:
+    // event declarations; events are represented as types, 
+    // and can carry a specific data for each event;
+    // but it's not needed for generator, so we define them later
+    struct play_event;
+    struct stop_event;
+    struct pause_event;
+
+    // transition functions
+    void do_play(play_event const&);
+    void do_stop(stop_event const&);
+    void do_pause(pause_event const&);
+    void do_resume(play_event const&);
+
+    // STT
+    friend class state_machine<player>;
+    typedef mpl::list<
+          transition<stopped, play_event,  playing, &player::do_play>
+        , transition<playing, stop_event,  stopped, &player::do_stop>
+        , transition<playing, pause_event, paused,  &player::do_pause>
+        , transition<paused,  play_event,  playing, &player::do_resume>
+        , transition<paused,  stop_event,  stopped, &player::do_stop>
+        >::type transition_table;
+};
+
+ +

That's all - the above will generate a complete FSM implementation according to our specification. The only thing we need before using it is the definition of the event types (that were just forward declared before):

+ +
+// event definitions
+struct player::play_event
+    : player::event
+{
+};
+
+// ...
+
+ +

The usage is simple as well:

+ +
+int main()
+{
+    // usage example
+    player p;
+    p.process_event(player::play_event());
+    p.process_event(player::pause_event());
+    p.process_event(player::play_event());
+    p.process_event(player::stop_event());
+    return 0;
+}
+
+
+ +
+
+
+

5.2. Related work

+
+
+ +

A notable prior work in the field of automation of general-purpose state machine implementation in C++ is the Robert Martin's State Machine Compiler [SMC]. The SMC takes an ASCII description of the machine's state transition table and produces C++ code that implements the FSM using a variation of State design pattern [Hun91], [GHJ+95]. Lafreniere [Laf00] presents another approach, where no external tools are used, and the FSMs are table driven.

+
+
+ +
+
+
+

6. Acknowledgements

+
+
+ +

Peter Dimov contributed the bind functionality without which compile-time lambda expressions wouldn't have been possible. The MPL implementation would have been much more difficult without Vesa Karvonen's wonderful Boost Preprocessor Metaprogramming Library. Authors are also greatly indebted to David B. Held who kindly volunteered to thoroughly edit this document. Of course, any remaining errors are exclusively ours.

+
+ +
+
+
+

References

+
+
+ +
+

[Abr01] David Abrahams and Carlos Pinto Coelho, Effects of Metaprogramming Style on Compilation Time, 2001

+
+ +
+

[Ale01] Andrei Alexandrescu, Modern C++ Design: Generic Programming and Design Patterns Applied, Addison-Wesley, ISBN 0-201-70431-5, 2001

+
+ +
+

[CE98] Krzysztof Czarnecki and Ulrich Eisenecker, Metalisp, http://home.t-online.de/home/Ulrich.Eisenecker/meta.htm

+
+ +
+

[CE00] Krzysztof Czarnecki and Ulrich Eisenecker, Generative Programming: Methods, Tools, and Applications, Addison-Wesley, ISBN 0-201-30977-7, 2000

+
+ +
+

[EBNF] ISO/IEC 14977:1996(E), Information technology — Syntactic metalanguage — Extended BNF, ISO/IEC, 1996

+
+ +
+

[GHJ+95] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns, Elements of Reusable Object-Oriented Software, Addison-Wesley, ISBN 0-201-63361-2, 1995

+
+ +
+

[HU79] Hopcroft and Ullman, Introduction to automata theory, languages and computations, Addison-Wesley, 1979

+
+ +
+

[Hud89] Paul Hudak, Conception, Evolution, and Application of Functional Programming Languages, ACM Computing Surveys, Association for Computing Machinery (ACM), ISSN 0360-0300, Vol. 21, No. 3, pp. 359-411, September, 1989

+
+ +
+

[Hun91] Immo Huneke, Finite State Machines: A Model of Behavior for C++, C++ Report, SIGS Publications Inc., ISSN 1040-6042, 1991

+
+ +
+

[ISO98] ISO/IEC 14882:1998(E), Programming languages — C++, ISO/IEC, 1998

+
+ +
+

[Joh79] Stephen C. Johnson, Yacc: Yet Another Compiler Compiler, UNIX Programmer's Manual, Vol. 2b, pp. 353-387, 1979

+
+ +
+

[Laf00] David Lafreniere, State Machine Design in C++, C/C++ User Journal, CMP Media LCC, ISSN 1075-2838, Vol. 18, No. 5, May 1998

+
+ +
+

[Loki] The Loki library, http://sourceforge.net/projects/loki-lib/

+
+ +
+

[Mar98] Robert C. Martin, UML Tutorial: Finite State Machines, C++ Report, SIGS Publications Inc., ISSN 1040-6042, June 1998

+
+ +
+

[MPLR] Boost MPL Library Reference Documentation, http://www.mywikinet.com/mpl/ref/Table_of_Content.html

+
+ +
+

[PRE] Vesa Karvonen, Boost Preprocessor Metaprogramming library, http://www.boost.org/libs/preprocessor/doc/

+
+ +
+

[SMC] Robert C. Martin, SMC - Finite State Machine Compiler (C++), http://www.objectmentor.com/resources/downloads/index

+
+ +
+

[STL94] A. A. Stepanov and M. Lee, The Standard Template Library, Hewlett-Packard Laboratories, 1994

+
+ +
+

[SPL] Boost Smart Pointer library, http://www.boost.org/libs/smart_ptr/

+
+ +
+

[SS75] Gerald J. Sussman and Guy L. Steele Jr., Scheme: An interpreter for extended lambda calculus, MIT AI Memo 349, Massachusetts Institute of Technology, May 1975

+
+ +
+

[TTL] Boost Type Traits library, http://www.boost.org/libs/type_traits/

+
+ +
+

[Vel95a] Todd Veldhuizen, Using C++ template metaprograms, C++ Report, SIGS Publications Inc., ISSN 1040-6042, Vol. 7, No. 4, pp. 36-43, May 1995

+
+ +
+

[Vel95b] Todd Veldhuizen, Expression templates, C++ Report, SIGS Publications Inc., ISSN 1040-6042, Vol. 7, No. 5, pp. 26-31, Jun 1995

+
+ +
+

[Unr] Erwin Unruh, Prime number computation, ANSI X3J16-94-0075/ISO WG21-462

+
+
+ +

+
+
+

1 Although it would be easy to implement pointed_type using partial specialization to distinguish the case where T is a pointer, if_ is likely to be the right tool for dealing with more complex conditionals. For the purposes of exposition, please suspend disbelief!

+
+ +
+

2 In fact it's already broken: apply_twice doesn't even fit the metafunction concept since it requires a template (rather than a type) as its first parameter, which breaks the metafunction protocol.

+
+ +
+

3 A more precise definition of these concepts can be found in the library reference documentation [MPLR].

+
+ +
+

4 Random access is almost as important at compile-time as it is at run-time. For example, searching for an item in a sorted random-access sequence using lower_bound can be much faster than performing the same operation on a forward-access-only list.

+
+ +
+

5 Here is another, even more elegant implementation:

+ +
+template< typename Sequence >
+struct largest
+{
+    typedef typename mpl::max_element<
+          mpl::transform_view<
+              Sequence
+            , mpl::size_of<_>
+            >
+        >::type type;
+};
+
+
+ +
+

6 Ideally, if going this route, all the templates should be re-implemented for every integral type - char, int, short, long, etc.

+
+ +
+

7 The same technique was suggested by Czarnecki and Eisenecker in [CE00].

+
+ +
+

8 It could be much more, depending on the complexity of the apply<...> expression, whose depth is added to the overall recursion depth.

+
+ +
+

9 This implementation detail is made relatively painless through heavy reliance on the Boost Preprocessor Library, so only one copy of the code needs to be maintained.

+
+ +
+

10 The events need to be passed to action functions, as they may contain some event-specific information for an action.

+
+
+
+ + + diff --git a/doc/paper/msxsl_build.bat b/doc/paper/msxsl_build.bat new file mode 100755 index 0000000..ca82add --- /dev/null +++ b/doc/paper/msxsl_build.bat @@ -0,0 +1,11 @@ +@echo off + +if "%4" == "" goto build +f:\msxsl\msxsl.exe f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\titlepage.templates.xml f:\home\depot\xml\stylesheets\docbook-xsl-1.52.2\template\titlepage.xsl | f:\msxsl\msxsl.exe - f:\msxsl\to_utf8.xsl -o f:\home\depot\xml\stylesheets\docbook-1.50.0\html\titlepage.templates.xsl + +:build +sx -x lower -x empty %2 >%3.xml +f:\msxsl\msxsl.exe %3.xml f:\home\depot\xml\stylesheets\docbook-xsl-1.50.0\html\my\%1 -o %3 +del %3.xml +f:\tidy\tidy.exe -config f:\tidy\config.txt -m %3 +f:\tidy\tidy_attr.py %3 diff --git a/doc/paper/src/abstract.sgml b/doc/paper/src/abstract.sgml new file mode 100644 index 0000000..3c6dc1d --- /dev/null +++ b/doc/paper/src/abstract.sgml @@ -0,0 +1,38 @@ + + + + + AlekseyGurtovoy + + MetaCommunications +
agurtovoy@meta-comm.com + + + + + DavidAbrahams + + Boost Consulting +
david.abrahams@rcn.com + + + + + + +This paper describes the &Boost; &Cxx; template metaprogramming library (&MPL;), an extensible compile-time framework of algorithms, sequences and metafunction classes. The library brings together important abstractions from the generic and functional programming worlds to build a powerful and easy-to-use toolset which makes template metaprogramming practical enough for the real-world environments. The &MPL; is heavily influenced by its run-time equivalent - the Standard Template Library (STL), a part of the C++ standard library , . Like the STL, it defines an open conceptual and implementation framework which can serve as a foundation for future contributions in the domain. The library's fundamental concepts and idioms enable the user to focus on solutions without navigating the universe of possible ad-hoc approaches to a given metaprogramming problem, even if no actual &MPL; code is used. The library also provides a compile-time lambda expression facility enabling arbitrary currying and composition of class templates, a feature whose runtime counterpart is often cited as missing from the STL. This paper explains the motivation, usage, design, and implementation of the &MPL; with examples of its real-life applications, and offers some lessons learned about &Cxx; template metaprogramming. + + + + +template metaprogramming +generic programming +programming languages +C++ +STL +type systems +polymorphism +compile-time + + + diff --git a/doc/paper/src/acknowl.sgml b/doc/paper/src/acknowl.sgml new file mode 100644 index 0000000..f91ab72 --- /dev/null +++ b/doc/paper/src/acknowl.sgml @@ -0,0 +1,10 @@ + + +
+Acknowledgements</> + +<para> +Peter Dimov contributed the <literal>bind</> functionality without which compile-time lambda expressions wouldn't have been possible. The &MPL; implementation would have been much more difficult without Vesa Karvonen's wonderful Boost Preprocessor Metaprogramming Library. Authors are also greatly indebted to David B. Held who kindly volunteered to thoroughly edit this document. Of course, any remaining errors are exclusively ours. +</> + +</section> diff --git a/doc/paper/src/body.sgml b/doc/paper/src/body.sgml new file mode 100644 index 0000000..bde300a --- /dev/null +++ b/doc/paper/src/body.sgml @@ -0,0 +1,41 @@ +<!doctype article public "-//OASIS//DTD DocBook V4.1//EN" +[ +<!-- abbreviations --> +<!entity mdash "-"> +<!entity Boost "<literal>Boost</>"> +<!entity Cxx "C++"> +<!entity C "C"> +<!entity MPL "MPL"> +<!entity BMPL "Boost Metaprogramming Library"> +<!entity mdat "metadata"> +<!entity mping "metaprogramming"> +<!entity mfn "metafunction"> +<!entity unspec "/*unspecified*/"> + +<!-- physical entities --> +<!entity abstract SYSTEM "abstract.sgml"> +<!entity introduction SYSTEM "introduction.sgml"> +<!entity usage SYSTEM "usage.sgml"> +<!entity typeselection SYSTEM "typeselection.sgml"> +<!entity metafunctions SYSTEM "metafunctions.sgml"> +<!entity sequences SYSTEM "sequences.sgml"> +<!entity lambda SYSTEM "lambda.sgml"> +<!entity codegeneration SYSTEM "codegeneration.sgml"> +<!entity example SYSTEM "example.sgml"> +<!entity acknowl SYSTEM "acknowl.sgml"> +<!entity references SYSTEM "references.sgml"> +]> + +<article> +<title>The Boost &Cxx; Metaprogramming Library</> + +&abstract; +&introduction; +&usage; +λ +&codegeneration; +&example; +&acknowl; +&references; + +</article> diff --git a/doc/paper/src/codegeneration.sgml b/doc/paper/src/codegeneration.sgml new file mode 100644 index 0000000..6a9227c --- /dev/null +++ b/doc/paper/src/codegeneration.sgml @@ -0,0 +1,96 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="codegeneration"> +<title>Code generation facilities</> + +<para> +There are cases, especially in the domain of numeric computation, when one wants to perform some part of the calculations at compile-time, and then pass the results to a run-time part of the program for further processing. For example, suppose one has implemented a complex compile-time algorithm that works with fixed-point arithmetic: +</> + +<programlisting> +<![CDATA[ +// fixed-point algorithm input +typedef mpl::vector< + mpl::fixed_c<-1,2345678> + , mpl::fixed_c<9,0001> + // .. + , mpl::fixed_c<3,14159> + > input_data; + +/* + complex compile-time algorithm +*/ +typedef /*...*/ result_data; +]]> +</> + +<para> +Suppose the <literal>result_data</> here is a sequence of <literal>mpl::fixed_c</> types that keeps the results of the algorithm, and now one wishes to feed that result to the run-time part of the algorithm. With &MPL; she can do this: +</> + +<programlisting> +<![CDATA[ +double my_algorithm() +{ + // passing the results to the run-time part of the program + std::vector<double> results; + results.reserve(mpl::size<result_data>::value); + mpl::for_each<numbers,_>( + boost::bind(&std::vector<double>::push_back, &results, _1) + ); + // ... +} +]]> +</> + +<para> +The <literal>for_each<numbers,_>(...)</> call is what actually transfers the compile-time <literal>result_data</> into run-time <literal>results</>. <literal>for_each</> is a function template declared as: +</> + +<programlisting> +<![CDATA[ +template< + typename Seq + , typename TransformOp + , typename F + > +void for_each(F f) +{ + // ... +} +]]> +</> + +<para>To call the function, one is required to explicitly provide two actual template parameters, a compile-time sequence <literal>Seq</> and a unary transformation metafunction <literal>TransformOp</>, plus a run-time function argument <literal>f</> (in our example, <literal>numbers</>, <literal>_</>, and <literal>boost::bind(...)</> correspondingly). <literal>f</> is a function object which <literal>operator()</> is called for every element in the <literal>Seq</> tranfromed by <literal>TransformOp</>. +</> + +<para> +Applying this to our example, the +</> + +<programlisting> +<![CDATA[ +mpl::for_each<numbers,_>( + boost::bind(&std::vector<double>::push_back, &results, _1) + ); +]]> +</> + +<para> +call is roughly equivalent to this: +</> + +<programlisting> +<![CDATA[ +f(mpl::apply< _,mpl::at_c<result_data,0>::type >::type()); +f(mpl::apply< _,mpl::at_c<result_data,1>::type >::type()); +// ... +f(mpl::apply< _,mpl::at_c<result_data,n>::type >::type()); +]]> +</> + +<para> +where <literal>n == mpl::size<result_data>::type::value</>. +</> + +</section> diff --git a/doc/paper/src/example.sgml b/doc/paper/src/example.sgml new file mode 100644 index 0000000..868a06f --- /dev/null +++ b/doc/paper/src/example.sgml @@ -0,0 +1,294 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="example"> +<title>Example: a compile-time FSM generator</> + +<para> +Finite state machines (<acronym>FSMs</>) are an important tool for describing and implementing program behavior <citation><xref linkend="ref.hu79"></>, <citation><xref linkend="ref.mar98"></>. They also are a good example of a domain in which &mping; can be applied to reduce the amount of repetitive and boilerplate operations one must perform in order to implement these simple mathematical models in code. Below we present a simple state machine generator that has been implemented using &BMPL; facilities. The generator takes a compile-time automata description, and converts it into &Cxx; code that implements the FSM at run-time. +</> + +<para> +The FSM description is basically a combination of states and events plus a state transition table (<acronym>STT</>), which ties them all together. The generator walks through the table and generates the state machine's <literal>process_event</> method that is the essence of an FSM. +</> + +<para> +Suppose we want to implement a simple music player using a finite state machine model. The state transition table +for the FSM is shown in <xref linkend="example.fsm.stt">. The STT format reflects the way one usually describes the behavior of an FSM in plain English. For example, the first line of the table can be read as follows: <quote>If the model is in the <literal>stopped</> state and the <literal>play_event</> is received, then the <literal>do_play</> transition function is called, and the model transitions to the <literal>playing</> state</>. +</> + +<table id="example.fsm.stt" frame="none"> +<title>Player's state transition table with actions</> + +<tgroup cols="4" align="left"> +<thead> +<row> + <entry>State</> + <entry>Event</> + <entry>Next state</> + <entry>Transition function</> +</> +</> + +<tbody> +<row> + <entry><literal>stopped</></> + <entry><literal>play_event</></> + <entry><literal>playing</></> + <entry><literal>do_play</></> +</> +<row> + <entry><literal>playing</></> + <entry><literal>stop_event</></> + <entry><literal>stopped</></> + <entry><literal>do_stop</></> +</> +<row> + <entry><literal>playing</></> + <entry><literal>pause_event</></> + <entry><literal>paused</></> + <entry><literal>do_pause</></> +</> +<row> + <entry><literal>paused</></> + <entry><literal>play_event</></> + <entry><literal>playing</></> + <entry><literal>do_resume</></> +</> +<row> + <entry><literal>paused</></> + <entry><literal>stop_event</></> + <entry><literal>stopped</></> + <entry><literal>do_stop</></> +</> +</> +</tgroup> + +</table> + +<para> +The transition table provides us with a complete formal definition of the target FSM, and there are several ways to +transform that definition into code. For instance, if we define states as members of an enumeration type, and events as classes derived from some base <literal>event</> class + +<footnote id="note.fsm"><para>The events need to be passed to action functions, as they may contain some event-specific information for an action.</></> + +, like so: +</> + +<programlisting> +<![CDATA[ +class player +{ + public: + // event declarations + struct event; + struct play_event; + struct stop_event; + struct pause_event; + + // "input" function + void process_event(event const&); // throws + + private: + // states + enum state_t { stopped, playing, paused }; + + // transition functions + void do_play(play_event const&); + void do_stop(stop_event const&); + void do_pause(pause_event const&); + void do_resume(play_event const&); + + private: + state_t m_state; +}; +]]> +</> + +<para> +then the most straightforward way to derive the FSM implementation from the above table would be something +like this: +</> + +<programlisting> +<![CDATA[ +void player::process_event(event const& e) +{ + if (m_state == stopped) + { + if (typeid(e) == typeid(play_event)) + { + do_play(static_cast<play_event const&>(e)); + m_state = playing; + return; + } + } + else if (m_state == playing) + { + if (typeid(e) == typeid(stop_event)) + { + do_stop(static_cast<stop_event const&>(e)); + m_state = stopped; + return; + } + + if (typeid(e) == typeid(pause_event)) + { + do_pause(static_cast<pause_event const&>(e)); + m_state = paused; + return; + } + } + else if (m_state == paused) + { + if (typeid(e) == typeid(stop_event)) + { + do_stop(static_cast<stop_event const&>(e)); + m_state = stopped; + return; + } + + if (typeid(e) == typeid(play_event)) + { + do_play(static_cast<play_event const&>(e)); + m_state = playing; + return; + } + } + else + { + throw logic_error( + boost::format("unknown state: %d") + % static_cast<int>(m_state) + ); + } + + throw std::logic_error( + "unexpected event: " + typeid(e).name() + ); +} +]]> +</> + +<para> +Although there is nothing particularly wrong with implementing an FSM's structure using nested <literal>if</> (or <literal>switch-case</>) statements, the obvious weakness of this approach is that most of the above code is boilerplate. What one tends to do with boilerplate code is to copy and paste it, then change names etc. to adjust it to its new location; and that's where the errors are most likely to creep in. Since all the lines of event processing look alike (structurally), it's very easy to overlook or forget something that needs to be changed, and many such errors won't appear until the runtime. +</> + +<para> +The transition table of our FSM is just five lines long; ideally, we would like the skeleton implementation of the automata's controlling logic to be equally short (or, at least, to look equally short, i.e. to be encapsulated in some form so we never worry about it). +</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="example.impl"> +<title>Implementation</> + +<para> +To represent the STT in a &Cxx; program, we define a <literal>transition</> class template that represents a single line of the table. Then the table itself can be represented as a sequence of such lines: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list< + transition<stopped, play_event, playing, &player::do_play> + , transition<playing, stop_event, stopped, &player::do_stop> + , transition<playing, pause_event, paused, &player::do_pause> + , transition<paused, play_event, playing, &player::do_resume> + , transition<paused, stop_event, stopped, &player::do_stop> + >::type transition_table; +]]></> + +<para> +Now, the complete FSM will look like this: +</> + +<programlisting> +<![CDATA[ +class player + : state_machine<player> +{ + private: + typedef player self_t; + + // state invariants + void stopped_state_invariant(); + void playing_state_invariant(); + void paused_state_invariant(); + + // states (invariants are passed as non-type template arguments, + // and are called then the FSM enters the corresponding state) + typedef state<0, &self_t::stopped_state_invariant> stopped; + typedef state<1, &self_t::playing_state_invariant> playing; + typedef state<2, &self_t::paused_state_invariant> paused; + + private: + // event declarations; events are represented as types, + // and can carry a specific data for each event; + // but it's not needed for generator, so we define them later + struct play_event; + struct stop_event; + struct pause_event; + + // transition functions + void do_play(play_event const&); + void do_stop(stop_event const&); + void do_pause(pause_event const&); + void do_resume(play_event const&); + + // STT + friend class state_machine<player>; + typedef mpl::list< + transition<stopped, play_event, playing, &player::do_play> + , transition<playing, stop_event, stopped, &player::do_stop> + , transition<playing, pause_event, paused, &player::do_pause> + , transition<paused, play_event, playing, &player::do_resume> + , transition<paused, stop_event, stopped, &player::do_stop> + >::type transition_table; +}; +]]> +</> + +<para> +That's all — the above will generate a complete FSM implementation according to our specification. The only thing we need before using it is the definition of the event types (that were just forward declared before): +</> + +<programlisting> +<![CDATA[ +// event definitions +struct player::play_event + : player::event +{ +}; + +// ... +]]> +</> + +<para> +The usage is simple as well: +</> + +<programlisting> +<![CDATA[ +int main() +{ + // usage example + player p; + p.process_event(player::play_event()); + p.process_event(player::pause_event()); + p.process_event(player::play_event()); + p.process_event(player::stop_event()); + return 0; +} +]]> +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="example.relatedwork"> +<title>Related work</> + +<para> +A notable prior work in the field of automation of general-purpose state machine implementation in &Cxx; is the Robert Martin's <emphasis>State Machine Compiler</> <citation><xref linkend="ref.smc"></>. The SMC takes an ASCII description of the machine's state transition table and produces &Cxx; code that implements the FSM using a variation of State design pattern <citation><xref linkend="ref.hun91"></>, <citation><xref linkend="ref.ghj95"></>. Lafreniere <citation><xref linkend="ref.laf00"></> presents another approach, where no external tools are used, and the FSMs are table driven. +</> +</section> + +</section> diff --git a/doc/paper/src/introduction.sgml b/doc/paper/src/introduction.sgml new file mode 100644 index 0000000..1dbfa81 --- /dev/null +++ b/doc/paper/src/introduction.sgml @@ -0,0 +1,375 @@ +<section id="intro"> +<title>Introduction</> + +<para> +Metaprogramming is usually defined as the creation of programs which generate other programs. Parser generators such as YACC <citation><xref linkend="ref.Joh79"></> are examples of one kind of program-generating program. The input language to YACC is a context-free grammar in Extended Backus-Naur Form <citation><xref linkend="ref.EBNF"></>, and its output is a program which parses that grammar. Note that in this case the metaprogram (YACC) is written in a language (&C;) which does not directly support the description of generated programs. These specifications, which we'll call <emphasis>&mdat;</>, are not written in &C;, but in a <emphasis>meta-language</>. Because the the rest of the user's program typically requires a general-purpose programming system and must interact with the generated parser, the &mdat; is translated into &C;, which is then compiled and linked together with the rest of the system. The &mdat; thus undergoes two translation steps, and the user is always very conscious of the boundary between her &mdat; and the rest of her program. +</> + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="intro.native"> +<title>Native language metaprogramming</> + +<para> +A more interesting form of &mping; is available in languages such as Scheme <citation><xref linkend="ref.SS75"></>, where the generated program specification is given in the same language as the metaprogram itself. The metaprogrammer defines her meta-language as a subset of the expressible forms of the underlying language, and program generation can take place in the same translation step used to process the rest of the user's program. This +allows users to switch transparently between ordinary programming, generated program specification, and &mping;, often without being aware of the transition. +</> +</section> + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="intro.cxx"> +<title>Metaprogramming in &Cxx;</> + +<para> +In &Cxx;, it was discovered almost by accident <citation><xref linkend="ref.Unr"></>, <citation><xref linkend="ref.Vel95a"></> that the template mechanism provides a rich facility for computation at compile-time. In this section, we'll explore the basic mechanisms and some common idioms used for metaprogramming in &Cxx;. +</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="intro.cxx.numeric"> +<title>Numeric computations</> + +<para> +The availability of <emphasis>non-type template parameters</> makes it possible to perform integer computations at compile-time. For example, the following template computes the factorial of its argument: +</> + +<programlisting> +<![CDATA[ +template< unsigned n > +struct factorial +{ + static const unsigned value = n * factorial<n-1>::value; +}; + +template<> +struct factorial<0> +{ + static const unsigned value = 1; +}; +]]> +</> + +<para> +The program fragment above is called a <emphasis>&mfn;</>, and it is easy to see its relationship to a function designed to be evaluated at runtime: the <quote>&mfn; argument</> is passed as a template parameter, and its <quote>return value</> is defined as a nested static constant. Because of the hard line between the expression of compile-time and runtime computation in &Cxx;, metaprograms look different from their runtime counterparts. Thus, although as in Scheme the &Cxx; metaprogrammer writes her code in the same language as the ordinary program, only a subset +of the full &Cxx; language is available to her: those expressions which can be evaluated at compile-time. Compare the above with a straightforward runtime definition of the factorial function: +</> + +<programlisting> +unsigned factorial(unsigned N) +{ + return N == 0 ? 1 : N * factorial(N - 1); +} +</> + +<para> +While it is easy to see the analogy between the two recursive definitions, recursion is in general more important to &Cxx; metaprograms than it is to runtime &Cxx;. In contrast to languages such as Lisp where recursion is idiomatic, &Cxx; programmers will typically avoid recursion when possible. This is done not only for efficiency reasons, but also because of <quote>cultural momentum</>: recursive programs are simply harder (for &Cxx; programmers) to think about. Like pure Lisp, though, the &Cxx; template mechanism is a <emphasis>functional</> programming language: as such it rules out the use of data mutation required to maintain loop variables. +</> + +<para> +A key difference between the runtime and compile-time factorial functions is the expression of the termination condition: our meta-factorial uses template specialization as a kind of <emphasis>pattern-matching</> mechanism to describe the behavior when <literal>N</> is zero. The syntactic analogue in the runtime world would require two separate definitions of the same function. In this case the impact of the second definition is minimal, but in large +metaprograms the cost of maintaining and understanding the terminating definitions can become significant. +</> + +<para> +Note also that a &Cxx; &mfn;'s return value must be <emphasis>named</>. The name chosen here, <literal>value</>, is the same one used for all numeric returns in the &MPL;. As we'll see, establishing a consistent naming +convention for &mfn; returns is crucial to the power of the library. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="intro.cxx.type"> +<title>Type computations</> + +<para> +How could we apply our <literal>factorial</> &mfn;? We might, for example, produce an array type of an appropriate size to hold all permutations of instances of another type: +</> + +<programlisting> +<![CDATA[ +// permutation_holder<T>::type is an array type which can contain +// all permutations of a given T. + +// unspecialized template for scalars +template< typename T > +struct permutation_holder +{ + typedef T type[1][1]; +}; + +// specialization for array types +template< typename T, unsigned N > +struct permutation_holder<T[N]> +{ + typedef T type[factorial<N>::value][N]; +}; +]]> +</> + +<para> +Here we have introduced the notion of a <emphasis>type computation</>. Like <literal>factorial</> above, <literal>permutation_holder</> template is a &mfn;. However, where <literal>factorial</> manipulates unsigned integer values, <literal>permutation_holder</> accepts and <quote>returns</> a type (as the nested typedef <literal>type</>). Because the &Cxx; type system provides a much richer set of expressions than anything we can use as a nontype template argument (e.g. the integers), &Cxx; metaprograms tend to be composed mostly of type computations. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="intro.cxx.seq"> +<title>Type sequences</> + +<para> +The ability to programmatically manipulate collections of types is a central tool of most interesting &Cxx; metaprograms. Because this capability is so well-supported by the &MPL;, we'll provide just a brief +introduction to the basics here. Later on, we'll revisit the example below to show how it can be implemented using &MPL;. +</> + +<para> +First, we'd need a way to represent the collection. One idea might be to store the types in a structure: +</> + +<programlisting> +<![CDATA[ +struct types +{ + int t1; + long t2; + std::vector<double> t3; +}; +]]> +</> + +<para> +Unfortunately, this arrangement is not susceptible to the compile-time type introspection power that &Cxx; gives us: there's no way to find out what the names of the members are, and even if we assume that they're named according to some convention as above, there's no way to know how many members there are. The key to solving this problem is to +increase the uniformity of the representation. If we have a consistent way to get the first type of any sequence and the rest of the sequence, we can easily access all members: +</> + +<programlisting> +<![CDATA[ +template< typename First, typename Rest > +struct cons +{ + typedef First first; + typedef Rest rest; +}; + +struct nil {}; + +typedef + cons<int + , cons<long + , cons<std::vector<double> + , nil + > > > my_types; +]]> +</> + +<para> +The structure described by <literal>types</> above is the compile-time analogue of a singly-linked list; it has been first introduced by Czarnecki and Eisenecker in <citation><xref linkend="ref.ce98"></>. Now that we've adjusted the structure so that the &Cxx; template machinery can <quote>peel it apart</>, let's examine a simple metafunction which does so. Suppose a user wished to find the largest of an arbitrary collection of types. We can apply the recursive &mfn; formula which should by now be familiar: +</> + +<example id="example.largest"> +<title>'largest' metafunction</> +<programlisting> +<![CDATA[ +// choose the larger of two types +template< + typename T1 + , typename T2 + , bool choose1 = (sizeof(T1) > sizeof(T2)) // hands off! + > +struct choose_larger +{ + typedef T1 type; +}; + +// specialization for the case where sizeof(T2) >= sizeof(T1) +template< typename T1, typename T2 > +struct choose_larger< T1,T2,false > +{ + typedef T2 type; +}; + +// get the largest of a cons-list +template< typename T > struct largest; + +// specialization to peel apart the cons list +template< typename First, typename Rest > +struct largest< cons<First,Rest> > + : choose_larger< First, typename largest<Rest>::type > +{ + // type inherited from base +}; + +// specialization for loop termination +template< typename First > +struct largest< cons<First,nil> > +{ + typedef First type; +}; + +int main() +{ + // print the name of the largest of my_types + std::cout + << typeid(largest<my_types>::type).name() + << std::endl + ; +} +]]> +</> +</> + +<para> +There are several things worth noticing about this code: +</> + +<itemizedlist mark="box"> + +<listitem><para> +It uses a few ad-hoc, esoteric techniques, or <quote>hacks</>. The default template argument <literal>choose1</> (labeled <quote>hands off!</>) is one example. Without it, we would have needed yet another template to provide the implementation of <literal>choose_larger</>, or we would have had to provide the computation explicitly as a parameter to the template - perhaps not bad for this example, but it would make <literal>choose_larger</> much less useful and more error-prone. The other hack is the derivation of a specialization of <literal>largest</> from <literal>choose_larger</>. This is a code-saving device which allows the programmer to avoid writing <quote><literal>typedef + typename </>...<literal>::type type</></> in the template body. +</></> + +<listitem><para> +Even this simple metaprogram uses three separate partial specializations. The <literal>largest</> &mfn; uses <emphasis>two</> specializations. One might expect that this indicates there are two termination conditions, but there are not: one specialization is needed simply to deal with access to the sequence elements. These specializations make the code difficult to read by spreading the definition of a single &mfn; over several &Cxx; template definitions. Also, because they are <emphasis>partial</> specializations, they make the code unusable for a large community of &Cxx; programmers whose compilers don't support that feature. +</></> + +</itemizedlist> + +<para> +While these techniques are, of course, a valuable part of the arsenal of any good &Cxx; metaprogrammer, their use tends to make programs written in what is already an unusual style harder-to-read and harder-to-write. By encapsulating commonly-used structures and dealing with loop terminations internally, the &MPL; reduces the need for both tricky hacks and for template specializations. +</> +</section> + +</section> + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="intro.whymetaprog"> +<title>Why metaprogramming?</> + +<!-- +maybe we don't need another example of a metaprogram given what +we've done above? We could rewrite and cut most of this section... +--> + +<para> +It's worth asking why anyone would want to do this. After all, even a simple toy example like the factorial &mfn; is somewhat esoteric. To show how the type computation can be put to work, let's examine a simple example. The following code produces an array containing all possible permutations of another array: +</> + +<programlisting> +<![CDATA[ +// can't return an array in C++, so we need this wrapper +template< typename T > +struct wrapper +{ + T x; +}; + +// return an array of the N! permutations of 'in' +template< typename T > +wrapper< typename permutation_holder<T>::type > +all_permutations(T const& in) +{ + wrapper<typename permutation_holder<T>::type> result; + + // copy the unpermutated array to the first result element + unsigned const N = sizeof(T) / sizeof(**result.x); + std::copy(&*in, &*in + N, result.x[0]); + + // enumerate the permutations + unsigned const result_size = sizeof(result.x) / sizeof(T); + for (T* dst = result.x + 1; dst != result.x + result_size; ++dst) + { + T* src = dst - 1; + std::copy(*src, *src + N, *dst); + std::next_permutation(*dst, *dst + N); + } + return result; +} +]]> +</> + +<!-- ...up to this point --> + +<para> +The runtime definition of <literal>factorial</> would be useless in <literal>all_permutations</> above, since in &Cxx; the sizes of array members must be computed at compile-time. However, there are alternative approaches; how could we avoid &mping;, and what would the consequences be? +</> + +<orderedlist> + +<listitem> +<para> +We could write programs to interpret the &mdat; directly. In our factorial example, the array size could have been a runtime quantity; then we'd have been able to use the straightforward factorial function. However, that would imply the use of dynamic allocation, which is often expensive. +</> +<para> +To carry this further, YACC might be rewritten to accept a pointer-to-function returning tokens from the stream to be parsed, and a string containing the grammar description. This approach, however, would impose unacceptable runtime costs for most applications: either the parser would have to treat the grammar nondeterministically, exploring the grammar for each parse, or it would have to begin by replicating at runtime the substantial table-generation and optimization work of the existing YACC for each input grammar. +</> +</> + +<listitem> +<para> +We could replace the compile-time computation with our own analysis. After all, the size of arrays passed to + <literal>all_permutations</> are always known at compile-time, and thus can be known to its user. We could ask the user to supply the result type explicitly: +</> + +<programlisting> +<![CDATA[ +template< typename Result, typename T > +Result all_permutations(T const& input); +]]> +</> + +<para> +The costs to this approach are obvious: we give up expressivity (by requiring the user to explicitly specify implementation details), and correctness (by allowing the user to specify them incorrectly). Anyone who has had to write parser tables by hand will tell you that the impracticality of this approach is the very reason of YACC's existence. +</> +<para> +In a language such as &Cxx;, where the &mdat; can be expressed in the same language as the rest of the user's program, expressivity is further enhanced: the user can invoke metaprograms directly, without learning a foreign syntax or interrupting the flow of her code. +</> +</> + +</orderedlist> + +<para> +So, the motivation for &mping; comes down to the combination of three factors: efficiency, expressivity, and correctness. While in classical programming there is always a tension between expressivity and correctness on one hand and efficiency on the other, in the &mping; world we wield new power: we can move the computation required for +expressivity from runtime to compile-time. +</> +</section> + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="intro.whylibrary"> +<title>Why a metaprogramming <emphasis>library</>?</> + +<para> +One might just as well ask why we need any generic library: +</> + +<itemizedlist mark="box"> + +<listitem> +<para> +Quality. Code that is appropriate for a general-purpose library is usually incidental to the purpose of its users. To a library developer, it is the central mission. On average, the containers and algorithms provided by any given &Cxx; standard library implementation are more-flexible and better-implemented than the project-specific implementations which abound, because library development was treated as an end in itself rather than a task incidental to the development of some other application. With a centralized implementation for any given function, optimizations and improvements are more likely to have been applied. +</> +</> + +<listitem> +<para> +Re-use. More important even than the re-use of code which all libraries provide, a well-designed generic library establishes a <emphasis>framework of concepts and idioms</> which establishes a reusable mental model for approaching problems. Just as the &Cxx; Standard Template Library gave us iterator concepts and a function object protocol, the &BMPL; provides type-iterators and metafunction class protocol. A well-considered framework of idioms saves the metaprogrammer from considering irrelevant implementation details and allows her to concentrate on the problem at hand. +</> +</> + +<listitem> +<para> +Portability. A good library can smooth over the ugly realities of platform differences. While in theory a &mping; library is fully generic and shouldn't be concerned with these issues, in practice support for templates remains inconsistent even four years after standardization. This should perhaps not be surprising: &Cxx; templates are the language's furthest-reaching and most complicated feature, which largely accounts for the power of &mping; in &Cxx;. +</> +</> + +<listitem> +<para> +Fun. Repeating the same idioms over and over is <emphasis>tedious</>. It makes programmers tired and reduces productivity. Furthermore, when programmers get bored they get sloppy, and buggy code is even more costly than slowly-written code. Often the most useful libraries are simply patterns that have been <quote>plucked</> by an astute programmer from a sea of repetition. The &MPL; helps to reduce boredom by eliminating the need for the most commonly-repeated boilerplate coding patterns. +</> +</> + +</itemizedlist> + +<para> +As one can see, the &MPL;'s development is motivated primarily by the same practical, real-world considerations that justify the development of any other library. Perhaps this is an indication that template &mping; is finally ready to leave the realm of the esoteric and enter the lingua franca of every day programmers. +</> + +<!-- probably this paragraph would be better in the conclusions --> +</section> + +</section> diff --git a/doc/paper/src/lambda.sgml b/doc/paper/src/lambda.sgml new file mode 100644 index 0000000..e778903 --- /dev/null +++ b/doc/paper/src/lambda.sgml @@ -0,0 +1,142 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="lambda"> +<title>Lambda facility</> + +<para> +The &MPL;'s lambda facility allows the <firstterm>inline composition</> of class templates into <quote>lambda expressions</>, which are classes and can therefore be passed around as ordinary metafunction classes, or transformed into metafunction classes before application using the expression: +</> + +<programlisting><![CDATA[ +typedef mpl::lambda<expr>::type func; +]]></> + +<para> +For example, <literal>boost::remove_const</> traits template from Boost <literal>type_traits</> library <citation><xref linkend="ref.TTL"></> is a class template (obviously), or a <link linkend="metafunctions">metafunction</> in &MPL; terminology. The simplest example of an <quote>inline composition</> of it would be something like: +</> + +<programlisting><![CDATA[ +typedef boost::remove_const<_1> expr; +]]></> + +<para> +This forms a so called <quote>lambda expression</>, which is neither a metafunction class, nor a metafunction, yet can be passed around everywhere because it's an ordinary &Cxx; class, because all &MPL; facilities are polymorphic with respect to their arguments. Now, that lambda expression can be <emphasis>transformed</> into a metafunction class using the &MPL;'s <literal>lambda</> facility: +</> + +<programlisting><![CDATA[ +typedef boost::remove_const<_1> expr; +typedef mpl::lambda<expr>::type func; +]]></> + +<para> +The <literal>func</> is a unary metafunction class and can be used as such. In particular, it can be pass around or invoked (applied): +</> + +<programlisting><![CDATA[ +typedef mpl::apply<func,int const>::type res; +BOOST_MPL_ASSERT_IS_SAME(res, int); +]]></> + +<para> +or even +</> + +<programlisting><![CDATA[ +typedef func::apply<int const>::type res; +BOOST_MPL_ASSERT_IS_SAME(res, int); +]]></> + +<para> +Inline composition is very appealing syntactically when one deals with metafunctions, because it makes the expression obvious: +</> + +<programlisting><![CDATA[ +typedef mpl::logical_or< + mpl::less< mpl::size_of<_1>, mpl::int_c<16> > + , boost::is_same<_1,_2> + > expr; + +typedef mpl::lambda<expr>::type func; +]]></> + +<para> +And one does not have to specify the last part (<literal>typedef lambda<expr>::type func</>), because all the algorithms do this to any of their metafunction class operands internally (a <literal>lambda<T>::type</> expression applied to a metafunction class gives back the same metafunction class, so it's safe to apply the expression unconditionally). +</> + +<para> +The alternative way to write an equivalent of the above metafunction class would be: +</> + +<programlisting><![CDATA[ +typedef bind< + mpl::meta_fun2<mpl::logical_or> + , mpl::bind< mpl::meta_fun2<mpl::less> + , mpl::bind< mpl::meta_fun1<mpl::size_of>,_1 > + , mpl::int_c<16> + > + , mpl::bind< mpl::meta_fun2<boost::is_same>,_1,_2 > + > func; +]]></> + +<para> +Or to use <literal>mpl::compose_</> family of templates in a similar way. Here, we use <literal>mpl::meta_fun</> templates to convert metafunctions into metafunction classes and then combine them using <literal>mpl::bind</>. The transformation from this form to the above inline lambda expression and vice-versa is mechanical, and that is essentially what the <literal>typedef mpl::lambda<expr>::type</> expression does. +</> + +<para> +For its own metafunctions (algorithms, primitives, etc.), &MPL; enables one to write the above in a less cumbersome way: +</> + +<programlisting><![CDATA[ +typedef mpl::bind< + mpl::logical_or<> + , mpl::bind< mpl::less<>, mpl::bind<mpl::size_of<>,_1>, mpl::int_c<16> > + , mpl::bind< mpl::make_f2<boost::is_same>, _1,_2 > + > func; +]]></> + +<para> +Note that we still have to wrap <literal>is_same</> into <literal>make_f2</>, because it's a foreign template. +</> + +<para> +Now, about combining class template metafunctions and metafunction classes in the single lambda expression - it can be done like this: +</> + +<programlisting><![CDATA[ +struct my_predicate +{ + template< typename T1, typename T2 > struct apply + { + //... + }; +}; + +typedef mpl::logical_or< + mpl::less< mpl::size_of<_>,mpl::int_c<16> > + , mpl::bind< my_predicate,_,_ > // here + > expr; +]]></> + +<para> +To bind something to one of its arguments (or change the order of parameters), then use either: +</> + +<programlisting><![CDATA[ +typedef mpl::logical_or< + mpl::less< mpl::size_of<_>,mpl::int_c<16> > + , mpl::bind<my_predicate,int,_>::type // here + > expr; +]]></> + +<para> +or +</> + +<programlisting><![CDATA[ +typedef mpl::logical_or< + mpl::less< mpl::size_of<_>,mpl::int_c<16> > + , my_predicate::apply<int,_> // here + > expr; +]]></> + +</section> diff --git a/doc/paper/src/metafunctions.sgml b/doc/paper/src/metafunctions.sgml new file mode 100644 index 0000000..eb31b12 --- /dev/null +++ b/doc/paper/src/metafunctions.sgml @@ -0,0 +1,282 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="metafunctions"> +<title>Metafunctions</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="metafunctions.simple"> +<title>The simple form</> + +<para> +In C++, the basic underlying language construct which allows parameterized compile-time computation is the <firstterm>class template</> (<citation><xref linkend="ref.ISO98"></>, section 14.5.1 [temp.class]). A bare class template is the simplest possible model we could choose for metafunctions: it can take types and/or non-type arguments as actual template parameters, and instantiation <quote>returns</> a new type. For example, the following produces a type derived from its arguments: +</> + +<programlisting> +<![CDATA[ +template< typename T1, typename T2 > +struct derive : T1, T2 +{ +}; +]]> +</> + +<para> +However, this model is far too limiting: it restricts the metafunction result not only to class types, but to instantiations of a given class template, to say nothing of the fact that every metafunction invocation introduces an additional level of template nesting. While that might be acceptable for this particular metafunction, any model which prevented us from <quote>returning</>, say, <literal>int</> is obviously not general enough. To meet this basic requirement, we must rely on a nested type to provide our return value: +</> + +<programlisting> +<![CDATA[ +template< typename T1, typename T2 > +struct derive +{ + struct type : N1, N2 {}; +}; + +// silly specialization, but demonstrates "returning" int +template<> +struct derive<void,void> +{ + typedef int type; +}; +]]> +</> + +<para> +Veldhuizen <citation><xref linkend="ref.Vel95a"></> was first to talk about class templates of this form as <quote>compile-time functions</>, and Czarnecki and Eisenecker <citation><xref linkend="ref.CE00"></> have introduced <quote>template metafunction</> as an equivalent term (they also use the simpler term <quote>metafunction</>, as do we). Czarnecki and Eisenecker have also recognized the limitations of the simple metafunction representation and suggested the form that we discuss in <xref linkend="metafunctions.classes">. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="metafunctions.higherorder"> +<title>Higher-order metafunctions</> + +<para> +While syntactically simple, the simple template metafunction form does not always interact optimally with the rest of &Cxx;. In particular, the simple metafunction form makes it unnecessarily awkward and tedious to define and work with higher-order metafunctions (metafunctions that operate on other metafunctions). In order to pass a simple metafunction to another template, we need to use <firstterm>template template parameters</>: +</> + +<programlisting> +<![CDATA[ +// returns F(T1,F(T2,T3)) +template< + template<typename> class F + , typename T1 + , typename T2 + , typename T3 + > +struct apply_twice +{ + typedef typename F< + T1 + , typename F<T2,T3>::type + >::type type; +}; + +// a new metafunction returning a type derived from T1, T2, and T3 +template< + typename T1 + , typename T2 + , typename T3 + > +struct derive3 + : apply_twice<derive,T1,T2,T3> +{ +}; +]]> +</> + +<para> +This looks different, but it seems to work. +<footnote id="note.higherorder"><para>In fact it's already broken: <literal>apply_twice</> doesn't even fit the metafunction concept since it requires a template (rather than a type) as its first parameter, which breaks the metafunction protocol.</></> + +However, things begin to break down noticeably when we want to <quote>return</> a metafunction from our metafunction: +</> + +<programlisting> +<![CDATA[ +// returns G s.t. G(T1,T2,T3) == F(T1,F(T2,T3)) +template< template<typename> class F > +struct compose_self +{ + template< + typename T1 + , typename T2 + , typename T3 + > + struct type + : apply_twice<F,T1,T2,T3> + { + }; +}; +]]> +</> + +<para> +The first and most obvious problem is that the result of applying <literal>compose_self</> is not itself a type, but a template, so it can't be passed in the usual ways to other metafunctions. A more subtle issue, however, is that the metafunction <quote>returned</> is not exactly what we intended. Although it acts just like <literal>apply_twice</>, it differs in one important respect: its identity. In the C++ type system, <literal>compose_self<F>::template type<T,U,V></> is not a synonym for <literal>apply_twice<F,T,U,V></>, and any metaprogram which compared metafunctions would discover that fact. +</> + +<para> +Because &Cxx; makes a strict distinction between type and class template template parameters, reliance on simple metafunctions creates a <quote>wall</> between metafunctions and metadata, relegating metafunctions to the status of second-class citizens. For example, recalling our introduction to type sequences, there's no way to make a <literal>cons</> list of metafunctions: +</> + +<programlisting> +<![CDATA[ +typedef cons<derive, cons<derive3, nil> > derive_functions; // error! +]]> +</> + +<para> +We might consider redefining our <literal>cons</> cell so we can pass <literal>derive</> as the head element: +</> + +<programlisting> +<![CDATA[ +template < + template< template<typename T, typename U> class F + , typename Tail + > +struct cons; +]]> +</> + +<para> +However, now we have another problem: &Cxx; templates are polymorphic with respect to their type arguments, but not with respect to template template parameters. The arity (number of parameters) of any template template parameter is strictly enforced, so we <emphasis>still</> can't embed <literal>derive3</> in a <literal>cons</> list. Moreover, polymorphism <emphasis>between</> types and metafunctions is not supported (the compiler expects one or the other), and as we've seen, the syntax and semantics of <quote>returned</> metafunctions is different from that of returned types. Trying to accomplish everything with the simple template metafunction form would seriously limit the applicability of higher-order metafunctions and would have an overall negative effect on the both conceptual and implementation clarity, simplicity and size of the library. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="metafunctions.classes"> +<title>Metafunction classes</> + +<para> +Fortunately, the truism that <quote>there is no problem in software which can't be solved by adding yet another level of indirection</> applies here. To elevate metafunctions to the status of first-class objects, the &MPL; introduces the concept of a <quote>metafunction class</>: +</> + +<programlisting> +<![CDATA[ +// metafunction class form of derive +struct derive +{ + template< typename N1, typename N2 > + struct apply + { + struct type : N1, N2 {}; + }; +}; +]]> +</> + +<para> +This form should look familiar to anyone acquainted with function objects in STL, with the nested <literal>apply</> template taking the same role as the runtime function-call operator. In fact, compile-time metafunction classes have the same relationship to metafunctions that runtime function objects have to functions: +</> + +<programlisting> +<![CDATA[ +// function form of add +template< typename T > T add(T x, T y) { return x + y; } + +// function object form of add +struct add +{ + template< typename T > + T operator()(T x, T y) { return x + y; } +}; +]]> +</> + +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="metafunctions.onesize"> +<title>One size fits all?</> + +<para> +The metafunction class form solves all the problems with ordinary template metafunction mentioned earlier: since it is a regular class, it can be placed in compile-time metadata sequences and manipulated by other metafunctions using the same protocols as for any other metadata. We thereby avoid the code-duplication needed to provide versions of each library component to operate on ordinary metadata and on metafunctions with each distinct supported arity. +</> + +<para> +On the other hand, it seems that accepting metafunction classes as <emphasis>the</> representation for compile-time function entities imposes code duplication danger as well: if the library's own primitives, algorithms, etc. are represented as class templates, that means that one either cannot reuse these algorithms in the context of higher-order functions, or she have to duplicate all algorithms in the second form, so, for instance, there would be two versions of <literal>find</>: +</> + +<programlisting> +<![CDATA[ +// user-friendly form +template< + typename Sequence + , typename T + > +struct find +{ + typedef /* ... */ type; +}; + +// "metafunction class" form +struct find_func +{ + template< typename Sequence, typename T > + struct apply + { + typedef /* ... */ type; + }; +}; +]]> +</> + +<para> +Of course, the third option is to eliminate <quote>user-friendly form</> completely so one would always have to write: +</> + +<programlisting> +<![CDATA[ +typedef mpl::find::apply<list,long>::type iter; +// or, if one prefers, +// typedef mpl::apply< mpl::find,list,long >::type iter; +]]> +</> + +<para> +instead of +</> + +<programlisting> +<![CDATA[ +typedef mpl::find<list,long>::type iter; +]]> +</> + +<para> +That too would hurt usability, considering that the direct invocations of library's algorithms are far more often-used than passing algorithms as arguments to other algorithms/metafunctions. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="metafunctions.lambda"> +<title>From metafunction to metafunction class</> + +<para> +The &MPL;'s answer to this dilemma is <firstterm>lambda expressions</>. Lambda is the mechanism that enables the library to curry metafunctions and convert them into metafunction classes, so when one wants to pass the <literal>find</> algorithm as an argument to a higher-order metafunction, she just write: +</> + +<programlisting> +<![CDATA[ +using namespace mpl::placeholder; +typedef mpl::apply< my_f, mpl::find<_1,_2> >::type result; +]]> +</> + +<para> +where <literal>_1</> and <literal>_2</> are placeholders for the first and second arguments to the resulting metafunction class. This preserves the intuitive syntax below for when the user wants to use <literal>find</> directly in her code: +</> + +<programlisting> +<![CDATA[ +typedef mpl::find<list,long>::type iter; +]]> +</> + +<para> +Lambda facility is described in more details in <xref linkend="lambda">. +</> + +</section> + +</section> diff --git a/doc/paper/src/references.sgml b/doc/paper/src/references.sgml new file mode 100644 index 0000000..0754a9c --- /dev/null +++ b/doc/paper/src/references.sgml @@ -0,0 +1,247 @@ +<bibliography id="refs"> +<title>References</> + +<biblioentry id="ref.Abr01"> + <abbrev>Abr01</> + <authorgroup> + <author><firstname>David</><surname>Abrahams</></> + <author><firstname>Carlos Pinto</><surname>Coelho</></> + </> + <title><ulink url="http://users.rcn.com/abrahams/instantiation_speed/index.html">Effects of Metaprogramming Style on Compilation Time</></> + <date>2001</> +</biblioentry> + +<biblioentry id="ref.Ale01"> + <abbrev>Ale01</> + <author><firstname>Andrei</><surname>Alexandrescu</></> + <title>Modern C++ Design: Generic Programming and Design Patterns Applied</> + <publishername>Addison-Wesley</> + <isbn>0-201-70431-5</> + <date>2001</> +</biblioentry> + +<biblioentry id="ref.CE98"> + <abbrev>CE98</> + <authorgroup> + <author><firstname>Krzysztof</><surname>Czarnecki</></> + <author><firstname>Ulrich</><surname>Eisenecker</></> + </> + <title>Metalisp</> + <bibliomisc><ulink url="http://home.t-online.de/home/Ulrich.Eisenecker/meta.htm"></></> +</biblioentry> + +<biblioentry id="ref.CE00"> + <abbrev>CE00</> + <authorgroup> + <author><firstname>Krzysztof</><surname>Czarnecki</></> + <author><firstname>Ulrich</><surname>Eisenecker</></> + </> + <title>Generative Programming: Methods, Tools, and Applications</> + <publishername>Addison-Wesley</> + <isbn>0-201-30977-7</> + <date>2000</> +</biblioentry> + +<biblioentry id="ref.EBNF"> + <abbrev>EBNF</> + <title>ISO/IEC 14977:1996(E), Information technology — Syntactic metalanguage — Extended BNF</> + <orgname>ISO/IEC</> + <date>1996</> +</biblioentry> + +<biblioentry id="ref.GHJ95"> + <abbrev>GHJ+95</> + <authorgroup> + <author><firstname>Erich</><surname>Gamma</></> + <author><firstname>Richard</><surname>Helm</></> + <author><firstname>Ralph</><surname>Johnson</></> + <author><firstname>John</><surname>Vlissides</></> + </> + <title>Design Patterns, Elements of Reusable Object-Oriented Software</> + <publishername>Addison-Wesley</> + <isbn>0-201-63361-2</> + <date>1995</> +</biblioentry> + +<biblioentry id="ref.HU79"> + <abbrev>HU79</> + <authorgroup> + <author><surname>Hopcroft</></> + <author><surname>Ullman</></> + </> + <title>Introduction to automata theory, languages and computations</> + <publishername>Addison-Wesley</> + <date>1979</> +</biblioentry> + +<biblioentry id="ref.Hud89"> + <abbrev>Hud89</> + <author><firstname>Paul</><surname>Hudak</></> + <title>Conception, Evolution, and Application of Functional Programming Languages</> + <biblioset relation='journal'> + <title>ACM Computing Surveys</> + <publishername>Association for Computing Machinery (ACM)</> + <issn>0360-0300</> + </> + <volumenum>21</> + <issuenum>3</> + <pagenums>359-411</> + <date>September, 1989</> +</biblioentry> + +<biblioentry id="ref.Hun91"> + <abbrev>Hun91</> + <author><firstname>Immo</><surname>Huneke</></> + <title>Finite State Machines: A Model of Behavior for C++</> + <biblioset relation='journal'> + <title>C++ Report</> + <publishername>SIGS Publications Inc.</> + <issn>1040-6042</> + </> + <date>1991</> +</biblioentry> + +<biblioentry id="ref.ISO98"> + <abbrev>ISO98</> + <title>ISO/IEC 14882:1998(E), Programming languages — C++</> + <orgname>ISO/IEC</> + <date>1998</> +</biblioentry> + +<biblioentry id="ref.Joh79"> + <abbrev>Joh79</> + <author><firstname>Stephen C.</><surname>Johnson</></> + <title><ulink url="http://dinosaur.compilertools.net/yacc/index.html">Yacc: Yet Another Compiler Compiler</></> + <publishername>UNIX Programmer's Manual</> + <volumenum>2b</> + <pagenums>353-387</> + <date>1979</> +</biblioentry> + +<biblioentry id="ref.Laf00"> + <abbrev>Laf00</> + <author><firstname>David</><surname>Lafreniere</></> + <title><ulink url="http://www.cuj.com/articles/2000/0005/0005f/0005f.htm?topic=articles">State Machine Design in C++</></> + <biblioset relation='journal'> + <title>C/C++ User Journal</> + <publishername>CMP Media LCC</> + <issn>1075-2838</> + </> + <volumenum>18</> + <issuenum>5</> + <date>May 1998</> +</biblioentry> + +<biblioentry id="ref.Loki"> + <abbrev>Loki</> + <title>The Loki library</> + <bibliomisc><ulink url="http://sourceforge.net/projects/loki-lib/"></></> +</biblioentry> + +<biblioentry id="ref.Mar98"> + <abbrev>Mar98</> + <author><firstname>Robert C.</><surname>Martin</></> + <title><ulink url="http://www.objectmentor.com/resources/articles/umlfsm.pdf">UML Tutorial: Finite State Machines</></> + <biblioset relation='journal'> + <title>C++ Report</> + <publishername>SIGS Publications Inc.</> + <issn>1040-6042</> + </> + <date>June 1998</> +</biblioentry> + +<biblioentry id="ref.MPLR"> + <abbrev>MPLR</> + <title>Boost MPL Library Reference Documentation</> + <bibliomisc><ulink url="http://www.mywikinet.com/mpl/ref/Table_of_Content.html"></></> +</biblioentry> + +<biblioentry id="ref.PRE"> + <abbrev>PRE</> + <author><firstname>Vesa</><surname>Karvonen</></> + <title>Boost Preprocessor Metaprogramming library</> + <bibliomisc><ulink url="http://www.boost.org/libs/preprocessor/doc/"></></> +</biblioentry> + +<biblioentry id="ref.SMC"> + <abbrev>SMC</> + <author><firstname>Robert C.</><surname>Martin</></> + <title>SMC - Finite State Machine Compiler (C++)</> + <bibliomisc><ulink url="http://www.objectmentor.com/resources/downloads/index"></></> +</biblioentry> + +<biblioentry id="ref.STL94"> + <abbrev>STL94</> + <authorgroup> + <author><surname>A. A. Stepanov</></> + <author><surname>M. Lee</></> + </authorgroup> + <title>The Standard Template Library</> + <orgname>Hewlett-Packard Laboratories</> + <date>1994</> +</biblioentry> + +<biblioentry id="ref.SPL"> + <abbrev>SPL</> + <title>Boost Smart Pointer library</> + <bibliomisc><ulink url="http://www.boost.org/libs/smart_ptr/"></></> +</biblioentry> + +<biblioentry id="ref.SS75"> + <abbrev>SS75</> + <authorgroup> + <author><firstname>Gerald J.</><surname>Sussman</></> + <author><firstname>Guy L.</><surname>Steele Jr.</></> + </> + <title>Scheme: An interpreter for extended lambda calculus</> + <biblioset relation='journal'> + <title>MIT AI Memo 349</> + <publishername>Massachusetts Institute of Technology</> + </> + <date>May 1975</> +</biblioentry> + +<biblioentry id="ref.TTL"> + <abbrev>TTL</> + <title>Boost Type Traits library</> + <bibliomisc><ulink url="http://www.boost.org/libs/type_traits/"></></> +</biblioentry> + +<biblioentry id="ref.vel95a"> + <abbrev>Vel95a</> + <author><firstname>Todd</><surname>Veldhuizen</></> + <title><ulink url="http://osl.iu.edu/~tveldhui/papers/Template-Metaprograms/meta-art.html">Using C++ template metaprograms</></> + <biblioset relation='journal'> + <title>C++ Report</> + <publishername>SIGS Publications Inc.</> + <issn>1040-6042</> + </> + <volumenum>7</> + <issuenum>4</> + <pagenums>36-43</> + <date>May 1995</> +</biblioentry> + +<biblioentry id="ref.Vel95b"> + <abbrev>Vel95b</> + <author><firstname>Todd</><surname>Veldhuizen</></> + <title><ulink url="http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html">Expression templates</></> + <biblioset relation='journal'> + <title>C++ Report</> + <publishername>SIGS Publications Inc.</> + <issn>1040-6042</> + </> + <volumenum>7</> + <issuenum>5</> + <pagenums>26-31</> + <date>Jun 1995</> +</biblioentry> + +<biblioentry id="ref.Unr"> + <abbrev>Unr</> + <author><firstname>Erwin</><surname>Unruh</></> + <title>Prime number computation</> + <publishername>ANSI X3J16-94-0075/ISO WG21-462</> +</biblioentry> + +</bibliography> diff --git a/doc/paper/src/sequences.sgml b/doc/paper/src/sequences.sgml new file mode 100644 index 0000000..1cc0b4f --- /dev/null +++ b/doc/paper/src/sequences.sgml @@ -0,0 +1,566 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="sequences"> +<title>Sequences, algorithms, and iterators</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.intro"> +<title>Introduction</> + +<para> +Compile-time iteration over a sequence (of types) is one of the basic concepts of template metaprogramming. Differences in types of objects being manipulated is the most common point of variability of similar but not identical code/design, and such designs are the direct target for some metaprogramming. Templates were originally designed to solve this exact problem (e.g. <literal>std::vector</>). However, without predefined abstractions/constructs for manipulating/iterating over <emphasis>sequences</> of types (as opposed to standalone types), and without known techniques for emulating these constructs using the current language facilities, their effect on helping high-level metaprogramming happen has been limited. +</> + +<para> +Czarnecki and Eisenecker <citation><xref linkend="ref.CE98"></>, <citation><xref linkend="ref.CE00"></> were the first to introduce compile-time sequences of types and some simple algorithms on them, although the idea of representing common data structures like trees, lists, etc. at compile time, using class template composition has been around for a while (e.g. most of the expression template libraries build such trees as a part of their expression "parsing" process <citation><xref linkend="ref.Vel95b"></>). Alexandrescu <citation><xref linkend="ref.Ale01"></> used lists of types and some algorithms on them to implement several design patterns; the accompanying code is known as the Loki library <citation><xref linkend="ref.Loki"></>. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.algo"> +<title>Algorithms and sequences</> + +<para> +Most of the algorithms in the &BMPL; operate on sequences. For example, searching for a type in a list looks like this: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list<char,short,int,long,float,double> types; +typedef mpl::find<types,long>::type iter; +]]> +</> + +<para> +Here, <literal>find</> accepts two parameters - a sequence to search (<literal>types</>) and the type to search for (<literal>long</>) - and returns an iterator <literal>iter</> pointing to the first element of the sequence such that <literal>iter::type</> is identical to <literal>long</>. If no such element exists, <literal>iter</> is identical to <literal>end<types>::type</>. Basically, this is how one would search for a value in a <literal>std::list</> or <literal>std::vector</>, except that <literal>mpl::find</> accepts the sequence as a single parameter, while <literal>std::find</> takes two iterators. Everything else is pretty much the same - the names are the same, the semantics are very close, there are iterators, and one can search not only by type, but also by using a predicate: +</> + +<programlisting> +<![CDATA[ +typedef mpl::find_if< types,boost::is_float<_> >::type iter; +]]></> + +<para> +This conceptual/syntactical similarity with the STL is not coincidental. Reusing the conceptual framework of the STL in the compile-time world allows us to apply familiar and sound approaches for dealing with sequential data structures. The algorithms and idioms which programmers already know from the STL can be applied again at compile-time. We consider this to be one of &MPL;'s greatest strengths, distinguishing it from earlier attempts to build a template metaprogramming library. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.concepts"> +<title>Sequence concepts</> + +<para> +In the <literal>find</> example above, we searched for the type in a sequence built using the <literal>mpl::list</> template; but <literal>list</> is not the only sequence that the library provides. Neither is <literal>mpl::find</> or any other algorithm hard-coded to work only with <literal>list</> sequences. <literal>list</> is just one model of &MPL;'s <phrase role="concept">Forward Sequence</> concept, and <literal>find</> works with anything that satisfies this concept's requirements. The hierarchy of sequence concepts in &MPL; is quite simple - a <phrase role="concept">Sequence</> is any compile-time entity for which <literal>begin<></> and <literal>end<></> produce iterators to the range of its elements; a <phrase role="concept">Forward Sequence</> is a Sequence whose iterators satisfy <phrase role="concept">Forward Iterator</> requirements; a <phrase role="concept">Bidirectional Sequence</> is a Forward Sequence whose iterators satisfy <phrase role="concept">Bidirectional Iterator</> requirements; finally, a <phrase role="concept">Random Access Sequence</> is a Bidirectional Sequence whose iterators satisfy <phrase role="concept">Random Access Iterator</> requirements. + +<footnote id="note.seqconcepts"><para> +A more precise definition of these concepts can be found in the library reference documentation <citation><xref linkend="ref.MPLR"></>. +</></> + +</> + +<para> +Decoupling algorithms from particular sequence implementations (through iterators) allows a metaprogrammer to create her own sequence types and to retain the rest of the library at her disposal. For example, one can define a <literal>tiny_list</> for dealing with sequences of three types as follows: +</> + +<programlisting> +<![CDATA[ +template< typename TinyList, long Pos > +struct tiny_list_item; + +template< typename TinyList, long Pos > +struct tiny_list_iterator +{ + typedef typename tiny_list_item<TinyList,Pos>::type type; + typedef tiny_list_iterator<TinyList, Pos-1> prior; + typedef tiny_list_iterator<TinyList, Pos+1> next; +}; + +template< typename T0, typename T1, typename T2 > +struct tiny_list +{ + typedef tiny_list_iterator<tiny_list, 0> begin; + typedef tiny_list_iterator<tiny_list, 3> end; + typedef T0 type0; + typedef T1 type1; + typedef T2 type2; +}; + +template< typename TinyList > +struct tiny_list_item<TinyList,0> +{ + typedef typename TinyList::type0 type; +}; + +template< typename TinyList > +struct tiny_list_item<TinyList,1> +{ + typedef typename TinyList::type1 type; +}; + +template< typename TinyList > +struct tiny_list_item<TinyList,2> +{ + typedef typename TinyList::type2 type; +}; +]]> +</> + +<para> +and then use it with any of the library algorithms as if it were <literal>mpl::list</>: +</> + +<programlisting> +<![CDATA[ +typedef tiny_list< char,short,int > types; +typedef mpl::transform< + types + , boost::add_pointer<_1> + >::type pointers; +]]> +</> + +<para> +Note that <literal>tiny_list</> is a model of Bidirectional Sequence; it would be a Random Access Sequence if we added <literal>advance</> and <literal>distance</> members to <literal>tiny_list_iterator</>: +</> + +<programlisting> +<![CDATA[ +template< typename TinyList, long Pos > +struct tiny_list_iterator +{ + static long const position = Pos; + + typedef typename tiny_list_item<TinyList,Pos>::type type; + typedef tiny_list_iterator<TinyList, Pos-1> prior; + typedef tiny_list_iterator<TinyList, Pos+1> next; + + template< typename N > struct advance + { + typedef tiny_list_iterator< + TinyList + , Pos + N::value + > type; + }; + + template< typename Other > struct distance + { + typedef mpl::integral_c< + long + , Other::position - position + > type; + }; +}; +]]> +</> + +<para> +While the <literal>tiny_list</> itself might be not that interesting (after all, it can hold only three elements), if the technique above could be automated so we would be able to define not-so-tiny sequences (with five, ten, twenty, etc. elements), it would be very valuable. + +<footnote id="note.tinylist"><para> +Random access is almost as important at compile-time as it is at run-time. For example, searching for an item in a sorted random-access sequence using <literal>lower_bound</> can be much faster than performing the same operation on a forward-access-only <literal>list</>. +</></> + +</> + +<para> +External code generation is an option, but there exists a solution within the language. However, it is not a template metaprogramming, but rather <emphasis>preprocessor metaprogramming</>. In fact, &MPL;'s <literal>vector</> - a fixed-size type sequence that provides random-access iterators - is implemented very much like the above <literal>tiny_list</> - using the Boost Preprocessor library <citation><xref linkend="ref.PRE"></>. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.revisited"> +<title>Ad hoc example revisited</> + +<para> +So, the library provides its users with almost complete compile-time equivalent of the STL framework. Does it help them to solve their metaprogramming tasks? Let's return to our earlier <link linkend="example.largest"><literal>largest</></> example to see if we can rewrite it in a better way with what &MPL; has to offer. Well, actually, there is not much to look at, because the &MPL; implementation is a one-liner (we'll spread it out here for readability) + +<footnote id="note.maxelement"><para>Here is another, even more elegant implementation:</> +<programlisting> +<![CDATA[ +template< typename Sequence > +struct largest +{ + typedef typename mpl::max_element< + mpl::transform_view< + Sequence + , mpl::size_of<_> + > + >::type type; +}; +]]></> +</> + +: +</> + +<programlisting> +<![CDATA[ +template< typename Sequence > +struct largest +{ + typedef typename mpl::max_element< + Sequence + mpl::less< + mpl::size_of<_1> + , mpl::size_of<_2> + > + >::type iter; + + typedef typename iter::type type; +}; +]]></> + +<para> +There are no more termination conditions with tricky pattern matching, no more partial specializations; and even more importantly, it's <emphasis>obvious</> what the above code does - even although it's all templates - something that one could not say about the original version. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.iterfold"> +<title>iter_fold as the main iteration algorithm</> + +<para> +For the purpose of examining a little bit more of the library's internal structure, let's look at how <literal>max_element</> from the above example is implemented. One might expect that <emphasis>now</> we will again see all these awkward partial specializations, esoteric pattern matching, etc. Well, let's see: +</> + +<programlisting> +<![CDATA[ +template< + typename Sequence + , typename Predicate + > +struct max_element +{ + typedef typename mpl::iter_fold< + Sequence + , typename mpl::begin<Sequence>::type + , if_< less< deref<_1>,deref<_2> >, _2, _1 > + >::type type; +}; +]]> +</> + +<para> +The first thing to notice here is that this algorithm is implemented in terms of another one: <literal>iter_fold</>. In fact, this is probably the most important point of the example, because nearly all other generic sequence algorithms in the library are implemented in terms of <literal>iter_fold</>. If a user should ever need to implement her own sequence algorithm, she'll almost certainly be able to do so using this primitive, which means she won't have to resort to implementing hand-crafted iteration, pattern matching of special cases for loop termination, or workarounds for lack of partial specialization. It also means that her algorithm will automatically benefit from any optimizations the library has implemented, (e.g. recursion unrolling), and that it will work with any sequence that is a model of ForwardSequence, because <literal>iter_fold</> does not require anything more of its sequence argument. +</> + +<para> +<literal>iter_fold</> algorithm is basically a compile-time equivalent of the <literal>fold</> or <literal>reduce</> functions that comprise the basic and well-known primitives of many functional programming languages. An analogy more familiar to a &Cxx; programmer would be the <literal>std::accumulate</> algorithm from the &Cxx; standard library (<citation><xref linkend="ref.ISO98"></>, section 26.4.1 [lib.accumulate]). However, <literal>iter_fold</> is designed to take advantage of the natural characteristics of recursive traversal: it accepts <emphasis>two</> metafunction class arguments, the first of which is applied to the state "on the way in" and the second of which is applied "on the +way out". +</> + +<para> +The interface to <literal>iter_fold</> is defined in &MPL; as follows: +</> + +<programlisting> +<![RCDATA[ +template< + typename Sequence + , typename InitialState + , typename ForwardOp + , typename BackwardOp = _1 + > +struct iter_fold +{ + typedef &unspec; type; +}; +]]> +</> + +<para> +The algorithm <quote>returns</> the result of two-way successive applications of binary <literal>ForwardOp</> and <literal>BackwardOp</> operations to iterators in range [<literal>begin<Sequence>::type</>, <literal>end<Sequence>::type</>) and previous result of an operation; the <literal>InitialState</> is logically placed before the sequence and included in the forward traversal. The result <literal>type</> is identical to <literal>InitialState</> if the sequence is empty. +</> + +<para> +The library also provides <literal>iter_fold_backward</>, <literal>fold</>, and <literal>fold_backward</> algorithms which wrap <literal>iter_fold</> to accommodate its most common usage patterns. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.numbers"> +<title>Sequences of numbers</> + +<para> +What we've seen so far were sequences (and algorithms on sequences) of types. It is both possible and easy to manipulate compile-time <emphasis>values</> using the library as well. The only thing to remember is that in &Cxx;, class template non-type template parameters give us one more example of non-polymorphic behavior. In other words, if one declared a metafunction to take a non-type template parameter (e.g. <literal>long</>) it's not possible to pass anything besides compile-time integral constants to it: +</> + +<programlisting> +<![CDATA[ +template< long N1, long N2 > +struct equal_to +{ + static bool const value = (N1 == N2); +}; + +equal_to<5,5>::value; // ok +equal_to<int,int>::value; // error! +]]> +</> + +<para> +And of course this doesn't work the other way around either: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list<1,2,3,4,5> numbers; // error! +]]> +</> + +<para> +While this may be an obvious limitation, it imposes yet another dilemma on the library design: on the one hand, we don't want to restrict users to type manipulations only, and on the other hand, full support for integral manipulations would require at least duplication of most of the library facilities + +<footnote id="note.nontype"><para>Ideally, if going this route, all the templates should be re-implemented for every integral type - <literal>char</>, <literal>int</>, <literal>short</>, <literal>long</>, etc. +</></> + +- the same situation as we would have if we had chosen to represent metafunctions as ordinary class templates. The solution for this issue is the same as well: we represent integral values by wrapping them in types + +<footnote id="note.valuewrapping"><para> +The same technique was suggested by Czarnecki and Eisenecker in <citation><xref linkend="ref.CE00"></>. +</></> + +. For example, to create a list of numbers one can write: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list< + mpl::int_c<1> + , mpl::int_c<2> + , mpl::int_c<3> + , mpl::int_c<4> + , mpl::int_c<5> + > numbers; +]]> +</> + +<para> +Wrapping integral constants into types to make them first-class citizens is important well inside metaprograms, +where one often doesn't know (and doesn't care) if the metafunctions she is using operate on types, integral values, other metafunctions, or something else, like fixed-point or rational numbers (<literal>mpl::fixed_c</> and <literal>mpl::rational_c</>). +</> + +<para> +But, from the user's perspective, the above example is much more verbose than the shorter, incorrect one. Thus, for the purpose of convenience, the library does provide users with a template that takes non-type template parameters, but offers a more compact notation: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list_c<long,1,2,3,4,5> numbers; +]]></> + +<para> +There is a similar <literal>vector</> counterpart as well: +</> + +<programlisting> +<![CDATA[ +typedef mpl::vector_c<long,1,2,3,4,5> numbers; +]]> +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.variety"> +<title>A variety of sequences</> + +<para> +Previous efforts to provide generalized metaprogramming facilities for &Cxx; have always concentrated on <literal>cons</>-style type lists and a few core algorithms like <literal>size</> and <literal>at</>, which are tied to the specific sequence implementation. Such systems have an elegant simplicity reminiscent of the analogous functionality in pure functional Lisp. It is much more time-consuming to implement even a basic set of the sequence algorithms provided by equivalent run-time libraries (the STL in particular), but if we have learned anything from the STL, it is that tying those algorithms' implementations to a specific sequence implementation is a misguided effort! +</> + +<para> +The truth is that there is no single <quote>best</> type sequence implementation for the same reasons that there will never be a single <quote>best</> runtime sequence implementation. Furthermore, there are <emphasis>already</> quite a number of type list implementations in use today; and just as the STL algorithms can operate on sequences which don't come from STL containers, so the MPL algorithms are designed to work with foreign type sequences. +</> + +<para> +It may be an eye-opening fact for some that type lists are not the only useful compile-time sequence. Again, the need for a variety of compile-time containers arises for the same reasons that we have lists, vectors, deques, and sets in the &Cxx; standard library — different containers have different functional and performance characteristics which determine not only applicability and efficiency of particular algorithms, but also the expressiveness or verbosity of the code that uses them. While runtime performance is not an issue for &Cxx; metaprograms, compilation speed is often a significant bottleneck to advanced &Cxx; software development <citation><xref linkend="ref.Abr01"></>. +</> + +<para> +The &MPL; provides five built-in sequences: <literal>list</>, <literal>list_c</> (really just a <literal>list</> of value wrappers), <literal>vector</>, a randomly-accessible sequence of fixed maximum size, <literal>vector_c</>, and <literal>range_c</>, a randomly-accessible sequence of consecutive integral values. More important, however, is its ability to adapt to arbitrary sequence types. The only core operations that a sequence is required to provide in order to be used with the library algorithms are <literal>begin<></> and <literal>end<></> metafunctions which "return" iterators into the sequence. As with the STL, it is the iterators which are used to implement most of the general-purpose sequence algorithms the library provides. Also, as with the STL, algorithm specialization is used to take advantage of implementation knowledge about particular sequences: many of the "basic" sequence operations such as <literal>back<></>, <literal>front<></>, <literal>size<></>, and <literal>at<></> are specialized on sequence type to provide a more efficient implementation than the fully generic version. +</> +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="sequences.unrolling"> +<title>Loop/recursion unrolling</> + +<para> +Almost coincidentally, loop unrolling can be as important to compile-time iterative algorithms as it is to runtime algorithms. To see why, one must first remember that all "loops" in &Cxx; metaprograms, are in fact, implemented with recursion, and that the template instantiation depth can be a valuable resource in a compiler implementation. In fact, Annex B of the &Cxx; standard (<citation><xref linkend="ref.ISO98"></>, annex B [limits]) <emphasis>recommends</> a minimum depth of 17 recursively nested template instantiations; but this is far too low for many serious metaprograms, some of which easily exceed the hard-coded instantiation limits of some otherwise excellent compilers. To see how this works in action, let's examine a straightforward implementation of the <literal>fold</> metafunction, which combines some algorithm state with each element of a sequence: +</> + +<programlisting> +<![CDATA[ +namespace aux { + +// unspecialized version combines the initial state and first element +// and recurses to process the rest +template< + typename Start + , typename Finish + , typename State + , typename BinaryFunction + > +struct fold_impl + : fold_impl< + typename Start::next + , Finish + , typename apply< + BinaryFunction + , State + , typename Start::type + >::type + , BinaryFunction + > +{ +}; + +// specialization for loop termination +template< + typename Finish + , typename State + , typename BinaryFunction + > +struct fold_impl<Finish,Finish,State,BinaryFunction> +{ + typedef State type; +}; + +} // namespace aux + +// public interface +template< + typename Sequence + , typename State + , typename ForwardOp + > +struct fold + : aux::fold_impl< + , typename begin<Sequence>::type + , typename end<Sequence>::type + , State + , typename lambda<ForwardOp>::type + > +{ +}; + +]]> +</> + +<para> +Although simple and elegant, this implementation will always incur at least as many levels of recursive template instantiation as there are elements in the input sequence. + +<footnote id="note.unrolling1"><para>It could be much more, depending on the complexity of the <literal>apply<...></> expression, whose depth is added to the overall recursion depth. +</></> + +The library addresses this problem by explicitly "unrolling" the recursion. To apply the technique to our <literal>fold</> example, we begin by factoring out a single step of the algorithm. Our <literal>fold_impl_step</> metafunction has two results: <literal>type</> (the next state), and <literal>iterator</> (the next sequence position). +</> + +<programlisting> +<![CDATA[ +template< + typename BinaryFunction + , typename State + , typename Start + , typename Finish + > +struct fold_impl_step +{ + typedef typename apply< + BinaryFunction + , State + , typename Start::type + >::type type; + + typedef typename Start::next iterator; +}; +]]> +</> + +<para> +As with our main algorithm implementation, we specialize for the loop termination condition so that the step becomes a no-op: +</> + +<programlisting> +<![CDATA[ +template< + typename BinaryFunction + , typename State + , typename Finish + > +struct fold_impl_step<BinaryFunction,State,Finish,Finish> +{ + typedef State type; + typedef Finish iterator; +}; +]]> +</> + +<para> +Now we can now reduce <literal>fold</>'s instantiation depth by any constant factor N simply by inserting N invocations of <literal>fold_impl_step</>. Here we've chosen a factor of 4: +</> + +<programlisting> +<![CDATA[ +template< + typename Start + , typename Finish + , typename State + , typename BinaryFunction + > +struct fold_impl +{ + private: + typedef fold_impl_step< + BinaryFunction + , State + , Start + , Finish + > next1; + + typedef fold_impl_step< + BinaryFunction + , typename next1::type + , typename next1::iterator + , Finish + > next2; + + typedef fold_impl_step< + BinaryFunction + , typename next2::type + , typename next2::iterator + , Finish + > next3; + + typedef fold_impl_step< + BinaryFunction + , typename next3::type + , typename next3::iterator + , Finish + > next4; + + typedef fold_impl_step< + typename next4::iterator + , Finish + , typename next4::type + , BinaryFunction + > recursion; + + public: + typedef typename recursion::type type; +}; +]]> +</> + +<para> +The &MPL; applies this unrolling technique across all algorithms with an unrolling factor tuned according to the demands of the &Cxx; implementation in use, and with an option for the user to override the value. + +<footnote id="note.unrolling2"><para> +This implementation detail is made relatively painless through heavy reliance on the Boost Preprocessor Library, so only one copy of the code needs to be maintained. +</></> + +This fact enables users to push beyond the metaprogramming limits they would usually encounter with more naive algorithm implementations. Experiments also show a small (up to 10%) increase in metaprogram instantiation speed on some compilers when loop unrolling is used. +</> +</section> + +</section> diff --git a/doc/paper/src/typeselection.sgml b/doc/paper/src/typeselection.sgml new file mode 100644 index 0000000..e8be749 --- /dev/null +++ b/doc/paper/src/typeselection.sgml @@ -0,0 +1,242 @@ + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="typeselection"> +<title>Conditional type selection</> + +<para> +Conditional type selection is the simplest basic construct of &Cxx; template metaprogramming. Veldhuizen <citation><xref linkend="ref.Vel95a"></> was the first to show how to implement it, and Czarnecki and Eisenecker <citation><xref linkend="ref.CE00"></> first presented it as a standalone library primitive. The &MPL; defines the corresponding facility as follows: +</> + +<programlisting> +<![RCDATA[ +template< + typename Condition + , typename T1 + , typename T2 + > +struct if_ +{ + typedef &unspec; type; +}; +]]> +</> + +<para> +Note that the first template parameter of the template is a type. +</> + +<programlisting> +<![CDATA[ +// usage/semantics +typedef mpl::if_<mpl::true_c,char,long>::type t1; +typedef mpl::if_<mpl::false_c,char,long>::type t2; + +BOOST_MPL_ASSERT_IS_SAME(t1, char); +BOOST_MPL_ASSERT_IS_SAME(t2, long); +]]> +</> + +<para> +The construct is important because template metaprograms often contain a lot of decision-making code, and, as we will show, spelling it manually every time via (partial) class template specialization quickly becomes impractical. The template is also important from the point of encapsulating the compiler workarounds. +</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="delayedeval"> +<title>Delayed evaluation</> + +<para> +The way the &Cxx; template instantiation mechanism works imposes some subtle limitations on applicability of the type selection primitive (<literal>if_</>), compared to a manually implemented equivalent of the selection code. For example, suppose we are implementing a <literal>pointed_type</> traits template such that <literal>pointed_type<T>::type</> instantiated for a <literal>T</> that is either a plain pointer (<literal>U*</>), <literal>std::auto_ptr<U></>, or any of the Boost smart pointers <citation><xref linkend="ref.SPL"></>, e.g. <literal>boost::scoped_ptr<U></>, will give us the pointed type (<literal>U</>): +</> + +<programlisting> +<![CDATA[ +BOOST_MPL_ASSERT_IS_SAME(pointed_type<my*>::type, my); +BOOST_MPL_ASSERT_IS_SAME(pointed_type< std::auto_ptr<my> >::type, my); +BOOST_MPL_ASSERT_IS_SAME(pointed_type< boost::scoped_ptr<my> >::type, my); +]]> +</> + +<para> +Unfortunately, the straightforward application of <literal>if_</> to this problem does not work: + +<footnote id="note.pointedtype"><para> +Although it would be easy to implement <literal>pointed_type</> using partial specialization to distinguish the case where <literal>T</> is a pointer, <literal>if_</> is likely to be the right tool for dealing with more complex conditionals. For the purposes of exposition, please suspend disbelief! +</></> + +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct pointed_type + : mpl::if_< + boost::is_pointer<T> + , typename boost::remove_pointer<T>::type + , typename T::element_type // #1 + > +{ +}; + +// the following code causes compilation error in line #1: +// name followed by "::" must be a class or namespace name +typedef pointed_type<char*>::type result; +]]> +</> + +<para> +Clearly, the expression <literal>typename T::element_type</> is not valid in the case of <literal>T == char*</>, and that's what the compiler is complaining about. Implementing the selection code manually solves the problem: +</> + +<programlisting> +<![CDATA[ +namespace aux { +// general case +template< typename T, bool is_pointer = false > +struct select_pointed_type +{ + typedef typename T::element_type type; +}; + +// specialization for plain pointers +template< typename T > +struct select_pointed_type<T,true> +{ + typedef typename boost::remove_pointer<T>::type type; +}; +} + +template< typename T > +struct pointed_type + : aux::select_pointed_type< + T, boost::is_pointer<T>::value + > +{ +}; +]]> +</> + +<para> +But this quickly becomes awkward if needs to be done repeatedly, and this awkwardness is compounded when partial specialization is not available. We can try to work around the problem as follows: +</> + +<programlisting> +<![CDATA[ +namespace aux { +template< typename T > +struct element_type +{ + typedef typename T::element_type type; +}; +} + +template< typename T > +struct pointed_type +{ + typedef typename mpl::if_< + boost::is_pointer<T> + , typename boost::remove_pointer<T>::type + , typename aux::element_type<T>::type + >::type type; +}; +]]> +</> + +<para> +but this doesn't work either - the access to the <literal>aux::element_type<T></>'s nested <literal>type</> member still forces the compiler to instantiate <literal>element_type<T></> with <literal>T == char*</>, and that instantiation is, of course, invalid. Also, although in our case this does not lead to a compile error, the <literal>boost::remove_pointer<T></> template always gets instantiated as well, and for the same reason (because we are accessing its nested <literal>type</> member). Unnecessary instantiation that is not fatal may or may be not a problem, depending on the <quote>weight</> of the template (how much the instantiation taxes the compiler), but a general rule of thumb would be to avoid such code. +</> + +<para> +Returning to our error, to make the above code compile, we need to factor the act of <quote>asking</> <literal>aux::element_type<T></> for its nested <literal>type</> out of the <literal>if_</> invocation. The fact that both the <literal>boost::remove_pointer<T></> trait template and <literal>aux::element_type<T></> use the same naming convention for their result types makes the refactoring easier: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct pointed_type +{ + private: + typedef typename mpl::if_< + boost::is_pointer<T> + , boost::remove_pointer<T> + , aux::element_type<T> + >::type func_; + + public: + typedef typename func_::type type; +}; +]]> +</> + +<para> +Now the compiler is guaranteed not to instantiate both <literal>boost::remove_pointer<T></> and <literal>aux::element_type<T></>, even although they are used as actual parameters to the <literal>if_</> template, so we are allowed to get away with <literal>aux::element_type<char*></> so long as it won't end up being selected as <literal>func_</>. +</> + +<para> +The above technique is so common in template metaprograms, that it even makes sense to facilitate the selection of a nested <literal>type</> member by introducing a high-level equivalent to <literal>if_</> - the one that will do the <literal>func_::type</> operation (that is called [nullary] metafunction class application) as a part of its invocation. The &MPL; provides such template - it's called <literal>apply_if</>. Using it, we can re-write the above code as simple as: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct pointed_type +{ + typedef typename mpl::apply_if< + boost::is_pointer<T> + , boost::remove_pointer<T> + , aux::element_type<T> + >::type type; +}; +]]> +</> + +<para> +To make our techniques review complete, let's consider a slightly different example - suppose we want to define a high-level wrapper around <literal>boost::remove_pointer</> traits template <citation><xref linkend="ref.TTL"></>, which will strip the pointer qualification conditionally. We will call it <literal>remove_pointer_if</>: +</> + +<programlisting> +<![CDATA[ +template< + typename Condition + , typename T + > +struct remove_pointer_if +{ + typedef typename mpl::if_< + Condition + , typename boost::remove_pointer<T>::type + , T + >::type type; +}; +]]> +</> + +<para> +Now the above works the first time, but it suffers from the problem we mentioned earlier - <literal>boost::remove_pointer<T></> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource <citation><xref linkend="ref.Abr01"></>, and it is wasted by unnecessary template instantiations. We've just seen how to deal with the problem when both arguments to <literal>if_</> are the results of nullary metafunction class applications, but in this example one of the arguments (<literal>T</>) is just a simple type, so the refactoring just doesn't seem possible. +</> + +<para> +The easiest way out of this situation would be to pass to <literal>if_</> a real nullary metafunction instead of <literal>T</> - the one that returns <literal>T</> on its invocation. The &MPL; provides a simple way to do it - we just substitute <literal>identity<T></> and <literal>apply_if</> for <literal>T</> and <literal>if_</>: +</> + +<programlisting> +<![CDATA[ +template< + typename Condition + , typename T + > +struct remove_pointer_if +{ + typedef typename mpl::apply_if< + Condition + , boost::remove_pointer<T> + , mpl::identity<T> + >::type type; +}; +]]> +</> + +<para> +which gives us exactly what we wanted. +</> +</section> +</section> diff --git a/doc/paper/src/usage.sgml b/doc/paper/src/usage.sgml new file mode 100644 index 0000000..608edf1 --- /dev/null +++ b/doc/paper/src/usage.sgml @@ -0,0 +1,8 @@ +<section id="usage"> +<title>Basic usage</> + +&typeselection; +&metafunctions; +&sequences; + +</section> diff --git a/doc/ref/Acknowledgements.html b/doc/ref/Acknowledgements.html new file mode 100644 index 0000000..ae9a422 --- /dev/null +++ b/doc/ref/Acknowledgements.html @@ -0,0 +1,7 @@ +<!doctype html public "-//ietf//dtd html//en"> +<html><head><title>boost::mpl::Acknowledgements + + +

[Home]Acknowledgements

The format and language of this reference documentation has been greatly influenced by the SGI's [Standard Template Library Programmer's Guide]. +


+Table of Content
Last edited July 17, 2002 9:04 am \ No newline at end of file diff --git a/doc/ref/Algorithms.html b/doc/ref/Algorithms.html new file mode 100644 index 0000000..f3d3072 --- /dev/null +++ b/doc/ref/Algorithms.html @@ -0,0 +1,40 @@ + +boost::mpl::Algorithms + + +

[Home]Algorithms

    +
  1. Iteration algorithms +
      +
    1. iter_fold +
    2. iter_fold_backward +
    3. fold +
    4. fold_backward +
    5. copy +
    6. copy_if +
    7. copy_backward +
    8. copy_backward_if +
    +
  2. Querying algorithms +
      +
    1. find +
    2. find_if +
    3. contains +
    4. count +
    5. count_if +
    6. equal +
    7. lower_bound +
    8. upper_bound +
    9. max_element +
    10. min_element +
    +
  3. Transformation algorithms +
      +
    1. transform +
    2. remove +
    3. remove_if +
    4. replace +
    5. replace_if +
    +
+


+Table of Content
Last edited July 20, 2002 12:00 am \ No newline at end of file diff --git a/doc/ref/Bidirectional_Iterator.html b/doc/ref/Bidirectional_Iterator.html new file mode 100644 index 0000000..3f89e03 --- /dev/null +++ b/doc/ref/Bidirectional_Iterator.html @@ -0,0 +1,50 @@ + +boost::mpl::Bidirectional Iterator + + +

[Home]Bidirectional Iterator

Description

+

+A Bidirectional Iterator is a Forward Iterator that provides a way to obtain the previous element in a sequence. +

+

+

Refinement of

+

+Forward Iterator +

+

Definitions

+
    +
  • a bidirectional iterator i is decrementable if there is a "previous" iterator, that is, if i::prior expression is well-defined; iterators pointing to the first element of the sequence are not decrementable. +
+

+

Valid expressions

+

+Bidirectional Iterator both defines a new expression and refines the one described in Forward Iterator. +

+ + + + +
 Expression  Expression type  
typename i::nextA model of Bidirectional Iterator
typename i::priorA model of Bidirectional Iterator
+

+

Expression semantics

+

+Semantics of an expression is defined only where it is not defined in Forward Iterator. +

+ + + +
 Expression  Complexity  Precondition  Semantics  Postcondition  
typename i::priorAmortized constant timei is decrementablei::prior is an iterator pointing to the previous element of the sequencei::prior is dereferencable and incrementable
+

+

Invariants

+

+For any bidirectional iterators i and j the following invariants always hold: +

+

    +
  • if i is incrementable, then i::next::prior is a null operation; similarly, if i is decrementable, i::prior::next is a null operation. +
+

+

See also

+

+Bidirectional Sequence, Forward Iterator, Random Access Iterator +


+Table of Content
Last edited July 15, 2002 11:33 am \ No newline at end of file diff --git a/doc/ref/Bidirectional_Sequence.html b/doc/ref/Bidirectional_Sequence.html new file mode 100644 index 0000000..3055fb8 --- /dev/null +++ b/doc/ref/Bidirectional_Sequence.html @@ -0,0 +1,35 @@ + +boost::mpl::Bidirectional Sequence + + +

[Home]Bidirectional Sequence

Description

+

+A Bidirectional Sequence is a Forward Sequence, which provides iterators that satisfy the Bidirectional Iterator requirements. +

+

Refinement of

+

+Forward Sequence +

+

Valid expressions

+

+Bidirectional Sequence does not define any new expressions beyond those defined in Forward Sequence. However, it refines the expression requirements. +

+ + + + +
 Expression  Expression type  
typename begin<s>::typeA model of Bidirectional Iterator
typename end<s>::typeA model of Bidirectional Iterator
+

+

Models

+

+

+

+

See also

+

+Forward Sequence, Random Access Sequence, Bidirectional Iterator +


+Table of Content
Last edited July 15, 2002 2:36 pm \ No newline at end of file diff --git a/doc/ref/Categorized_index.html b/doc/ref/Categorized_index.html new file mode 100644 index 0000000..c4a8480 --- /dev/null +++ b/doc/ref/Categorized_index.html @@ -0,0 +1,84 @@ + +boost::mpl::Categorized index + + +

[Home]Categorized index

Concepts

+

+

+

+

Components

+ +


+Table of Content
Last edited July 17, 2002 8:58 am \ No newline at end of file diff --git a/doc/ref/Extensible_Sequence.html b/doc/ref/Extensible_Sequence.html new file mode 100644 index 0000000..89cd27d --- /dev/null +++ b/doc/ref/Extensible_Sequence.html @@ -0,0 +1,40 @@ + +boost::mpl::Extensible Sequence + + +

[Home]Extensible Sequence

Description

+

+An Extensible Sequence is either a Forward Sequence, a Bidirectional Sequence or a Random Access Sequence that supports insertion and removal operations. +

+

Refinement of

+

+Forward Sequence, Bidirectional Sequence or Random Access Sequence +

+

Valid expressions

+

+ + + + + + +
 Expression  Expression type  
typename clear<s>::typeA model of concept of s
typename insert<s,pos,T>::typeA model of concept of s
typename erase<s,pos>::typeA model of concept of s
typename erase<s,first,last>::typeA model of concept of s
+

+

Expression semantics

+

+See the description of clear, insert, and erase algorithms. +

+

Models

+

+

+

+

See also

+

+Sequences, clear, insert, erase +


+Table of Content
Last edited July 16, 2002 6:27 pm \ No newline at end of file diff --git a/doc/ref/Forward_Iterator.html b/doc/ref/Forward_Iterator.html new file mode 100644 index 0000000..f3c9bd8 --- /dev/null +++ b/doc/ref/Forward_Iterator.html @@ -0,0 +1,34 @@ + +boost::mpl::Forward Iterator + + +

[Home]Forward Iterator

Description

+

+A Forward Iterator is an Input Iterator that guarantees a linear traversal over the sequence. +

+

Refinement of

+

+Input Iterator +

+

+

Valid expressions

+

+Forward Iterator does not define any new expressions beyond those defined in Input Iterator. However, some of the restrictions described in Input Iterator are relaxed. +

+ + + +
 Expression  Expression type  
typename i::nextA model of Forward Iterator
+

+

Invariants

+

+For any forward iterators i and j the following invariants always hold: +

    +
  • if i and j are dereferenceable and i is identical to j, then i::next is identical to j::next. +
+

+

See also

+

+Forward Sequence, Input Iterator, Bidirectional Iterator +


+Table of Content
Last edited July 15, 2002 10:53 am \ No newline at end of file diff --git a/doc/ref/Forward_Sequence.html b/doc/ref/Forward_Sequence.html new file mode 100644 index 0000000..ce76f57 --- /dev/null +++ b/doc/ref/Forward_Sequence.html @@ -0,0 +1,48 @@ + +boost::mpl::Forward Sequence + + +

[Home]Forward Sequence

Description

+

+A Forward Sequence is a Sequence which guarantees that its elements are arranged in a definite order, and that the ordering will not change spontaneously [1]. Iterators into a forward sequence satisfy the Forward Iterator requirements. +

+

Refinement of

+

+Sequence +

+

Valid expressions

+

+Forward Sequence does not define any new expressions beyond those defined in Sequence. However, it refines the expression requirements. +

+ + + + +
 Expression  Expression type  
typename begin<s>::typeA model of Forward Iterator
typename end<s>::typeA model of Forward Iterator
+

+

Invariants

+

+For any forward sequence s the following invariants always hold: +

    +
  • Two different iterations through s will access its elements in the same order. +
+

+

Models

+

+

+

+

Notes

+

+[1] Both between compilation sessions and from iteration to iteration.
+

+

See also

+

+Sequence, Bidirectional Sequence, Forward Iterator +


+Table of Content
Last edited July 15, 2002 2:34 pm \ No newline at end of file diff --git a/doc/ref/Input_Iterator.html b/doc/ref/Input_Iterator.html new file mode 100644 index 0000000..36a304f --- /dev/null +++ b/doc/ref/Input_Iterator.html @@ -0,0 +1,44 @@ + +boost::mpl::Input Iterator + + +

[Home]Input Iterator

Description

+

+An Input Iterator is a Trivial Iterator that provides a way to obtain the next iterator in a sequence. +

+

Refinement of

+

+Trivial Iterator +

+

Definitions

+

+

    +
  • an input iterator is past-the-end if it points beyond the last element of a sequence; past-the-end iterators are non-dereferenceable; +
  • an input iterator is valid if it is dereferenceable or past-the-end; +
  • an input iterator i is incrementable if there is a "next" iterator, that is, if i::next expression is well-defined; past-the-end iterators are not incrementable; +
  • an input iterator j is reachable from a forward iterator i if, after recursive application of next operation to i a finite number of times, i is identical to j; +
  • the notation [i,j) refers to a range of iterators beginning with i and up to but not including j; +
  • the range [i,j) is a valid range if both i and j are valid iterators, and j is reachable from i. +
+

+

Valid expressions

+

+In addition to the expressions defined in Trivial Iterator, the following expressions must be valid. +

+ + + +
 Expression  Expression type  
typename i::nextA model of Input Iterator
+

+

Expression semantics

+

+ + + +
 Expression  Complexity  Precondition  Semantics  Postcondition  
typename i::nextAmortized constant timei is incrementablei::next is the next iterator in a sequencei::next is dereferenceable or past-the-end
+

+

See also

+

+Sequence, Trivial Iterator, Forward Iterator +


+Table of Content
Last edited July 15, 2002 10:48 am \ No newline at end of file diff --git a/doc/ref/Integral_Constant.html b/doc/ref/Integral_Constant.html new file mode 100644 index 0000000..50ee484 --- /dev/null +++ b/doc/ref/Integral_Constant.html @@ -0,0 +1,43 @@ + +boost::mpl::Integral Constant + + +

[Home]Integral Constant

Description

+

+An Integral Constant is a class (or a template class) that represents a value of a built-in integral type (bool, int, long, etc.) in compile-time programs. An integral constant directly supports the increment/decrement operations within the range of the built-in integral type it wraps. Other arithmetic operations are supported through the external metafunctions. +

+

Valid expressions

+

+ + + + + + + +
 Expression  Return type  
typename n::value_typeAn integral type
typename n::typeA model of Integral Constant
n::valueA compile-time integral constant of n::value_type
typename n::nextA model of Integral Constant
typename n::priorA model of Integral Constant
+

+

Expression semantics

+

+ + + + + + + +
 Expression  Complexity  Precondition  Semantics  Postcondition  
typename n::value_typeAmortized constant timen::value_type is identical to typeof(n::value)
typename n::typeAmortized constant timeSelf-reference.is_same<n::type,n>::value == true
n::valueAmortized constant timeValue of n.
typename n::nextAmortized constant timen::value_type supports an increment operation; n::value is incrementableIncrement operationn::next::value == n::value + 1
typename n::priorAmortized constant timen::value_type supports an decrement operation; n::value is decrementableDecrement operationn::next::value == n::value - 1
+

+

Models

+

+

    +
  • integral_c +
  • int_c +
  • bool_c +
+

+

See also

+

+next, prior +


+Table of Content
Last edited July 17, 2002 7:05 am \ No newline at end of file diff --git a/doc/ref/Iterators.html b/doc/ref/Iterators.html new file mode 100644 index 0000000..f15f209 --- /dev/null +++ b/doc/ref/Iterators.html @@ -0,0 +1,25 @@ + +boost::mpl::Iterators + + +

[Home]Iterators

Iterators are the mechanism that makes it possible to decouple algorithms from concrete compile-time sequence implementations. +

+

    +
  1. Concepts +
      +
    1. Trivial Iterator +
    2. Input Iterator +
    3. Forward Iterator +
    4. Bidirectional Iterator +
    5. Random Access Iterator +
    +
  2. Algorithms +
      +
    1. iterator_category +
    2. begin/end +
    3. advance +
    4. distance +
    +
+


+Table of Content
Last edited July 17, 2002 6:16 am \ No newline at end of file diff --git a/doc/ref/Metafunction.html b/doc/ref/Metafunction.html new file mode 100644 index 0000000..b4d1a8e --- /dev/null +++ b/doc/ref/Metafunction.html @@ -0,0 +1,60 @@ + +boost::mpl::Metafunction + + +

[Home]Metafunction

Description

+

+A Metafunction is a class template that represents a function invocable at compile-time. A metafunction is invoked by instantiating the class template with particular template parameters (metafunction arguments); the result of metafunction application is accessible through the instantiation's nested type typedef. A metafunction can have a variable number of parameters. +

+

Example

+

+

+// binary metafunction
+template< typename T1, typename T2 >
+struct is_same
+{
+    typedef false_c type;
+};
+

+template< typename T > +struct is_same +{ + typedef true_c type; +}; +

+// metafunction invocation +typedef is_same<int,char>::type res; +BOOST_STATIC_ASSERT(!res::value); +

+

+

+

Valid expressions

+

+ + + + +
 Expression  Expression type  
typename f::typeA type
typename f<t1,..,tn>::typeA type
+

+

Expression semantics

+

+ + + + +
 Expression  Complexity  Precondition  Semantics  Postcondition 
typename f::typeMetafunction dependentf is a nullary metafunction; f::type is a type-namef::type is the result of the metafunction invocation
typename f<t1,..,tn>::typeMetafunction dependentf is an n-ary metafunction; t1,..,tn are types; f<t1,..,tn>::type is a type-namef<t1,..,tn>::type is the result of the metafunction invocation with the input arguments t1,..,tn
+

+

Models

+

+

+

+

See also

+

+Metafunctions, [Metafunction Class] +


+Table of Content
Last edited July 16, 2002 11:27 pm \ No newline at end of file diff --git a/doc/ref/Metafunctions.html b/doc/ref/Metafunctions.html new file mode 100644 index 0000000..283419e --- /dev/null +++ b/doc/ref/Metafunctions.html @@ -0,0 +1,39 @@ + +boost::mpl::Metafunctions + + +

[Home]Metafunctions

    +
  1. Concepts +
      +
    1. Metafunction +
    +
  2. Metafunction +
      +
    1. Arithmetic operations +
        +
      1. plus +
      2. minus +
      3. multiplies +
      4. divides +
      5. modulus +
      6. negate +
      +
    2. Comparisons +
        +
      1. equal_to +
      2. not_equal_to +
      3. less +
      4. greater +
      5. less_equal +
      6. greater_equal +
      +
    3. Logical operations +
        +
      1. logical_or +
      2. logical_and +
      3. logical_not +
      +
    +
+


+Table of Content
Last edited July 17, 2002 8:46 am \ No newline at end of file diff --git a/doc/ref/Random_Access_Iterator.html b/doc/ref/Random_Access_Iterator.html new file mode 100644 index 0000000..3f294c4 --- /dev/null +++ b/doc/ref/Random_Access_Iterator.html @@ -0,0 +1,48 @@ + +boost::mpl::Random Access Iterator + + +

[Home]Random Access Iterator

Description

+

+A Random Access Iterator is a Bidirectional Iterator that provides constant-time methods for moving forward and backward on a sequence in arbitrary-sized steps. +

+

+

Refinement of

+

+Bidirectional Iterator +

+

Valid expressions

+

+Random Access Iterator defines two new expressions and refines the ones described in Bidirectional Iterator. +

+ + + + + + +
 Expression  Expression type  
typename i::nextA model of Random Access Iterator
typename i::priorA model of Random Access Iterator
typename i::template advance<n>::typeA model of Random Access Iterator
typename i::template distance<j>::typeA model of Integral Constant
+

+

Expression semantics

+

+Semantics of an expression is defined only where it is not defined in Bidirectional Iterator. +

+ + + + +
 Expression  Complexity  Precondition  Semantics  Postcondition  
typename i::template advance<n>::typeAmortized constant timeIncluding i itself, there must be n::value dereferenceable or past-the-end iterators following or preceding i, depending on whether n is positive or negative.If n::value > 0, equivalent to executing i::next n::value times; if n::value < 0, equivalent to executing i::prior n::value times; if n::value == 0, this is a null operation [1].The resulting iterator is dereferenceable or past-the-end.
typename i::template distance<j>::typeAmortized constant timeEither i is reachable from j or j is reachable from i, or both.Returns an integral constant n such that i::template advance<n>::type is identical to j.
+

+

Invariants

+

+For any random access iterators i and j the following invariants always hold: +

+

    +
  • if i::advance<n>::type is well-defined, then i::advance<n>::type::advance< negate<n>::type >::type is a null operation. +
+

+

See also

+

+Random Access Sequence, Bidirectional Iterator +


+Table of Content
Last edited July 15, 2002 11:35 am \ No newline at end of file diff --git a/doc/ref/Random_Access_Sequence.html b/doc/ref/Random_Access_Sequence.html new file mode 100644 index 0000000..16c2bab --- /dev/null +++ b/doc/ref/Random_Access_Sequence.html @@ -0,0 +1,35 @@ + +boost::mpl::Random Access Sequence + + +

[Home]Random Access Sequence

Description

+

+A Random Access Sequence is a Bidirectional Sequence which provides iterators that satisfy the Random Access Iterator requirements. A random access sequence provides amortized constant time access to arbitrary elements. +

+

Refinement of

+

+Bidirectional Sequence +

+

Valid expressions

+

+Random Access Sequence does not define any new expressions beyond those defined in Bidirectional Sequence. However, it refines the expression requirements. +

+ + + + +
 Expression  Expression type  
typename begin<s>::typeA model of Random Access Iterator
typename end<s>::typeA model of Random Access Iterator
+

+

Models

+

+

+

+

See also

+

+Bidirectional Sequence, Random Access Iterator +


+Table of Content
Last edited July 15, 2002 2:37 pm \ No newline at end of file diff --git a/doc/ref/Reference/advance.html b/doc/ref/Reference/advance.html new file mode 100644 index 0000000..2b25e10 --- /dev/null +++ b/doc/ref/Reference/advance.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/advance + + +

[Home]advance

Synopsis

+

+

+template<
+      typename Iterator
+    , typename N
+    >
+struct advance
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns an new iterator i such as distance< Iterator,i >::type::value == N::value. +

+

Definition

+

+

+#include "boost/mpl/advance.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
IteratorA model of Input Iterator
NA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef advance<Iterator,N>::type i;A model of Input IteratorIterator and every iterator between Iterator and i (inclusive) is nonsingular; N::value must be nonnegative if Iterator is a model of Input Iterator or Forward IteratorEquivalent to typedef Iterator::next i1; typedef i1::next i2; .. typedef in-1::next i; if N::value > 0, and typedef Iterator::prior i1; typedef i1::prior i2; .. typedef in-1::prior i; otherwise; if N::value == 0, the algorithm has no effect.distance< Iterator,i >::type::value == N::value
+

+

Complexity

+

+Amortized constant time if Iterator is a model of Random Access Iterator, otherwise linear time. +

+

Example

+

+

+typedef vector_c<int,0,1,2,3,4,5,6,7,8,9> numbers;
+typedef begin<numbers>::type first;
+typedef end<numbers>::type last;
+typedef advance_c<first,10>::type iter1;
+typedef advance_c<last,-10>::type iter2;
+BOOST_MPL_ASSERT_IS_SAME(iter1, last);
+BOOST_MPL_ASSERT_IS_SAME(iter2, first);
+
+

+

See also

+

+Iterators, Sequence, distance, begin, end +


+Table of Content | Reference
Last edited July 17, 2002 6:38 am \ No newline at end of file diff --git a/doc/ref/Reference/at.html b/doc/ref/Reference/at.html new file mode 100644 index 0000000..5567599 --- /dev/null +++ b/doc/ref/Reference/at.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/at + + +

[Home]at

Synopsis

+

+

+template<
+      typename N
+    , typename Sequence
+    >
+struct at
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a type identical to the N-th element from the beginning of the sequence. +

+

Definition

+

+

+#include "boost/mpl/at.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
NA model of Integral ConstantThe offset from the beginning of the sequence that specifies the element to be retrieved.
SequenceA model of Forward SequenceA sequence to be examined.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef at<N,Sequence>::type t;A type0 <= N::value < size<Sequence>::type::valueEquivalent to typedef advance< begin<Sequence>::type,N >::type::type t;
+

+

Complexity

+

+Depends on the implementation of the particular sequence it is applied to. Linear in the worst case, or amortized constant time. +

+

Example

+

+

+typedef range_c<long,10,50> range;
+BOOST_STATIC_ASSERT(at< int_c<0>, range >::type::value == 10);
+BOOST_STATIC_ASSERT(at< int_c<10>, range >::type::value == 20);
+BOOST_STATIC_ASSERT(at< int_c<40>, range >::type::value == 50);
+
+

+

See also

+

+Forward Sequence, at_c, front, back +


+Table of Content | Reference
Last edited July 17, 2002 3:49 am \ No newline at end of file diff --git a/doc/ref/Reference/at_c.html b/doc/ref/Reference/at_c.html new file mode 100644 index 0000000..7a3b2a2 --- /dev/null +++ b/doc/ref/Reference/at_c.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/at c + + +

[Home]at_c

Synopsis

+

+

+template<
+      long n
+    , typename Sequence
+    >
+struct at_c
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a type identical to the n-th element from the beginning of the sequence. at_c<n,Sequence>::type is a shorcut notation for at< integral_c<long,n>, Sequence>::type. +

+

Definition

+

+

+#include "boost/mpl/at.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
nAn compile-time integral constantAn offset from the beginning of the sequence that specifies the element to be retrieved.
SequenceA model of Forward SequenceA sequence being examined.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef at_c<n,Sequence>::type t;A type0 <= n < size<Sequence>::type::valueEquivalent to typedef at< integral_c<long,n>, Sequence>::type t;
+

+

Complexity

+

+Depends on the implementation of the particular sequence it is applied to. Linear in the worst case, or amortized constant time. +

+

Example

+

+

+typedef range_c<long,10,50> range;
+BOOST_STATIC_ASSERT(at_c<0,range>::type::value == 10);
+BOOST_STATIC_ASSERT(at_c<10,range>::type::value == 20);
+BOOST_STATIC_ASSERT(at_c<40,range>::type::value == 50);
+
+

+

See also

+

+Forward Sequence, at, front, back +


+Table of Content | Reference
Last edited July 17, 2002 3:50 am \ No newline at end of file diff --git a/doc/ref/Reference/back.html b/doc/ref/Reference/back.html new file mode 100644 index 0000000..0ce7a8c --- /dev/null +++ b/doc/ref/Reference/back.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/back + + +

[Home]back

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct back
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a type identical to the last element in the sequence, that is, the element in a position that preceeds the position of past-the-end iterator. +

+

Definition

+

+

+#include "boost/mpl/back.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to be examined.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef back<Sequence>::type t;A typeempty<Sequence>::type::value == falseEquivalent to typedef prior< end<Sequence>::type >::type::type t;
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef range_c<int,0,1> range1;
+typedef range_c<int,0,10> range2;
+typedef range_c<int,-10,0> range3;
+

+BOOST_STATIC_ASSERT(back<range1>::type::value == 0); +BOOST_STATIC_ASSERT(back<range2>::type::value == 9); +BOOST_STATIC_ASSERT(back<range3>::type::value == -1); +

+

+

Notes

+

+[1] The algorithm is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Forward Sequence, front, at, end, push_back +


+Table of Content | Reference
Last edited July 17, 2002 3:47 am \ No newline at end of file diff --git a/doc/ref/Reference/begin.html b/doc/ref/Reference/begin.html new file mode 100644 index 0000000..a301168 --- /dev/null +++ b/doc/ref/Reference/begin.html @@ -0,0 +1,56 @@ + +boost::mpl::Reference/begin + + +

[Home]begin

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct begin
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns an iterator that points to the first element of the sequence. +

+

Definition

+

+

+#include "boost/mpl/begin_end.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Sequence
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef begin<Sequence>::type first;A model of Input Iteratorfirst is an iterator pointing to the first element of the Sequence; equivalent to Sequence::begin unless the algorithm has been specialized for the particular type of sequence.first is either dereferenceable or past-the-end; it is past-the-end if and only if size<Sequence>::type::value == 0.
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef vector<unsigned char,unsigned short,unsigned int, unsigned long> unsigned_types;
+typedef begin<unsigned_types>::type iter;
+BOOST_STATIC_ASSERT((boost::is_same<iter::type,unsigned char>::value));
+
+

+

See also

+

+Iterators, Sequence, end, size, empty +


+Table of Content | Reference
Last edited July 22, 2002 2:03 am \ No newline at end of file diff --git a/doc/ref/Reference/clear.html b/doc/ref/Reference/clear.html new file mode 100644 index 0000000..29e03b0 --- /dev/null +++ b/doc/ref/Reference/clear.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/clear + + +

[Home]clear

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct clear
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns an empty sequence that preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/clear.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible Sequence
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef clear<Sequence>::type s;A model of Extensible SequenceEquivalent to typedef erase<Sequence, begin<Sequence>::type, end<Sequence>::type>::type s;empty<s>::type::value == true
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef list_c<int,1,3,5,7,9,11> odds;
+typedef clear<odds>::type nothing;
+BOOST_STATIC_ASSERT(empty<nothing>::type::value);
+
+

+

Notes

+

+[1] The algorithm is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Extensible Sequence, erase, empty, begin, end +


+Table of Content | Reference
Last edited July 17, 2002 3:58 am \ No newline at end of file diff --git a/doc/ref/Reference/contains.html b/doc/ref/Reference/contains.html new file mode 100644 index 0000000..f2a667e --- /dev/null +++ b/doc/ref/Reference/contains.html @@ -0,0 +1,58 @@ + +boost::mpl::Reference/contains + + +

[Home]contains

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct contains
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if one or more elements in Sequence are identical to T, and false_c otherwise. +

+

Definition

+

+

+#include "boost/mpl/contains.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to be examined.
TA typeThe type to search for.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef contains<Sequence,T>::type c;A model of bool Integral ConstantEquivalent to typedef logical_not< is_same< find<Sequence,T>::type, end<Sequence>::type > >::type c;
+

+

Complexity

+

+Linear. At most size<Sequence>::value comparisons for identity. +

+

Example

+

+

+typedef vector<char,int,unsigned,long,unsigned long> types;
+typedef contains<types,bool>::type result;
+BOOST_STATIC_ASSERT(!result::value);
+
+

+

See also

+

+Algorithms, find, find_if, count, count_if +


+Table of Content | Reference
Last edited July 17, 2002 4:48 am \ No newline at end of file diff --git a/doc/ref/Reference/copy.html b/doc/ref/Reference/copy.html new file mode 100644 index 0000000..1dec84a --- /dev/null +++ b/doc/ref/Reference/copy.html @@ -0,0 +1,70 @@ + +boost::mpl::Reference/copy + + +

[Home]copy

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BinaryOp
+    >
+struct copy
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+copy is, in fact, just another name for fold. It was introduced for symmetry with copy_if [1], and because it's a nice name for one of the typical fold applications, that is, copying the content of one sequence into another - see the example below. +

+

Definition

+

+

+#include "boost/mpl/copy.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BinaryOp application.
BinaryOpA model of [Lambda Function]The operation to be executed on forward traversal.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef copy<Sequence,T,Op>::type s;A typeEquivalent to typedef fold< Sequence,T,Op >::type s;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of BinaryOp. +

+

Example

+

+

+typedef vector_c<int,0,1,2,3,4,5,6,7,8,9> numbers;
+typedef copy<
+      range_c<int,10,20>
+    , push_back<_,_>
+    , numbers
+    >::type result;
+

+BOOST_STATIC_ASSERT(size<result>::value == 20); +BOOST_STATIC_ASSERT((equal< result,range_c<int,0,20> >::type::value)); +

+

+

Notes

+

+[1] In case if you wonder why copy_if, in its turn, wasn't just called fold_if, - something that would allow to eliminate the family of copy algorithms completely - these two have quite different semantics.
+

+

See also

+

+Algorithms, copy_if, copy_backward, copy_backward_if, fold, fold_backward +


+Table of Content | Reference
Last edited July 19, 2002 2:10 am \ No newline at end of file diff --git a/doc/ref/Reference/copy_backward.html b/doc/ref/Reference/copy_backward.html new file mode 100644 index 0000000..183d86c --- /dev/null +++ b/doc/ref/Reference/copy_backward.html @@ -0,0 +1,70 @@ + +boost::mpl::Reference/copy backward + + +

[Home]copy_backward

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BinaryOp
+    >
+struct copy_backward
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+copy_backward is, in fact, just another name for fold_backward. It was introduced for symmetry with copy_backward_if [1], and because it's a nice name for one of the typical fold_backward applications, that is, copying the content of one sequence into another - see the example below. +

+

Definition

+

+

+#include "boost/mpl/copy_backward.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BinaryOp application.
BinaryOpA model of [Lambda Function]The operation to be executed on backward traversal.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef copy_backward<Sequence,T,Op>::type s;A typeEquivalent to typedef fold_backward< Sequence,T,Op >::type s;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of BinaryOp. +

+

Example

+

+

+typedef list_c<int,10,11,12,13,14,15,16,17,18,19>::type numbers;
+typedef copy_backward<
+      range_c<int,0,10>
+    , push_front<_,_>
+    , numbers
+    >::type result;
+

+BOOST_STATIC_ASSERT(size<result>::value == 20); +BOOST_STATIC_ASSERT((equal< result,range_c<int,0,20> >::type::value)); +

+

+

Notes

+

+[1] In case if you wonder why copy_backward_if, in its turn, wasn't just called fold_backward_if, - something that would allow to eliminate the family of copy_backward algorithms completely - these two have quite different semantics.
+

+

See also

+

+Algorithms, copy_backward_if, copy, copy_if, fold, fold_backward +


+Table of Content | Reference
Last edited July 19, 2002 2:11 am \ No newline at end of file diff --git a/doc/ref/Reference/copy_backward_if.html b/doc/ref/Reference/copy_backward_if.html new file mode 100644 index 0000000..a6608fd --- /dev/null +++ b/doc/ref/Reference/copy_backward_if.html @@ -0,0 +1,70 @@ + +boost::mpl::Reference/copy backward if + + +

[Home]copy_backward_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BinaryOp
+    , typename Pred
+    >
+struct copy_backward_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of BinaryOp to the result of the previous BinaryOp invocation (State if it's the first call) and every element in the range [begin<Sequence>::type,end<Sequence>::type) that satisfies the predicate Pred, in the reverse order. A typical application for copy_backward_if is to conditionally copy the content of one sequence into another - see the example below. +

+

Definition

+

+

+#include "boost/mpl/copy_backward_if.hpp"
+
+

+

Parameters

+ + + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BinaryOp application.
BinaryOpA model of [Lambda Function]The operation to be executed on backward traversal.
PredAn unary Predicate [Lambda Expression]The copying condition.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef copy_backward_if<Sequence,T,Op,Pred>::type s;A typeEquivalent to typedef lambda<Op>::type op; typedef lambda<Pred>::type pred; typedef fold_backward< Sequence,T,if_< apply<pred,_2>, apply<op,_1,_2>, _1 > >::type s;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of Pred, and at most size<Sequence>::type::value applications of BinaryOp. +

+

Example

+

+

+typedef list_c<int,0,1,2,3,4,5,6,7,8,9>::type numbers;
+typedef list_c<int,0,1,2,3,4>::type answer;
+typedef copy_backward_if<
+      numbers
+    , list_c<int>
+    , push_front<_,_>
+    , less<_,int_c<5> >
+    >::type result;
+

+BOOST_STATIC_ASSERT(size<result>::value == 5); +BOOST_STATIC_ASSERT((equal<result,answer>::type::value)); +

+

+

See also

+

+Algorithms, copy_backward, copy_if, copy, fold, fold_backward +


+Table of Content | Reference
Last edited July 19, 2002 2:09 am \ No newline at end of file diff --git a/doc/ref/Reference/copy_if.html b/doc/ref/Reference/copy_if.html new file mode 100644 index 0000000..4b22920 --- /dev/null +++ b/doc/ref/Reference/copy_if.html @@ -0,0 +1,70 @@ + +boost::mpl::Reference/copy if + + +

[Home]copy_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BinaryOp
+    , typename Pred
+    >
+struct copy_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of BinaryOp to the result of the previous BinaryOp invocation (State if it's the first call) and every element in the range [begin<Sequence>::type,end<Sequence>::type) that satisfies the predicate Pred, in the linear order. A typical application for copy_if is to conditionally copy the content of one sequence into another - see the example below. +

+

Definition

+

+

+#include "boost/mpl/copy_if.hpp"
+
+

+

Parameters

+ + + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BinaryOp application.
BinaryOpA model of [Lambda Function]The operation to be executed on forward traversal.
PredAn unary Predicate [Lambda Expression]The copying condition.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef copy_if<Sequence,T,Op,Pred>::type s;A typeEquivalent to typedef lambda<Op>::type op; typedef lambda<Pred>::type pred; typedef fold< Sequence,T,if_< apply<pred,_2>, apply<op,_1,_2>, _1 > >::type s;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of Pred, and at most size<Sequence>::type::value applications of BinaryOp. +

+

Example

+

+

+typedef list_c<int,0,1,2,3,4,5,6,7,8,9>::type numbers;
+typedef list_c<int,0,1,2,3,4>::type answer;
+typedef copy_if<
+      numbers
+    , vector_c<int>
+    , push_back<_,_>
+    , less<_,int_c<5> >
+    >::type result;
+

+BOOST_STATIC_ASSERT(size<result>::value == 5); +BOOST_STATIC_ASSERT((equal<result,answer>::type::value)); +

+

+

See also

+

+Algorithms, copy, copy_backward_if, copy_backward, fold, iter_fold +


+Table of Content | Reference
Last edited July 19, 2002 2:10 am \ No newline at end of file diff --git a/doc/ref/Reference/count.html b/doc/ref/Reference/count.html new file mode 100644 index 0000000..8f3cf6d --- /dev/null +++ b/doc/ref/Reference/count.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/count + + +

[Home]count

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct count
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the number of elements in a Sequence that are identical to T. +

+

Definition

+

+

+#include "boost/mpl/count_if.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to be examined.
TA typeThe type to be searched for.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef count<Sequence,T>::type n;A model of Integral ConstantEquivalent to typedef count_if< Sequence,is_same<_,T> >::type n;
+

+

+

Complexity

+

+Linear. Exactly size<Sequence>::value comparisons for identity. +

+

Example

+

+

+typedef list<int,char,long,short,char,short,double,long> types;
+typedef find<types, short>::type iter;
+BOOST_STATIC_ASSERT((is_same<iter::type,short>::type::value));
+BOOST_STATIC_ASSERT((distance< begin<types>::type,iter >::type::value == 3));
+
+

+

See also

+

+Algorithms, count_if, find, find_if, contains +


+Table of Content | Reference
Last edited July 17, 2002 4:32 am \ No newline at end of file diff --git a/doc/ref/Reference/count_if.html b/doc/ref/Reference/count_if.html new file mode 100644 index 0000000..a5d4bf2 --- /dev/null +++ b/doc/ref/Reference/count_if.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/count if + + +

[Home]count_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pred
+    >
+struct count_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the number of elements in a Sequence that satisfy the predicate Pred. +

+

Definition

+

+

+#include "boost/mpl/count_if.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to be examined.
PredA model of Predicate [Lambda Expression]The count condition.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef count_if<Sequence,Pred>::type n;A model of Integral ConstantEquivalent to typedef lambda<Pred>::type pred; typedef fold< Sequence,integral_c<unsigned long,0>,if_<pred,next<_1>,_1> >::type n;
+

+

+

Complexity

+

+Linear. Exactly size<Sequence>::value applications of Pred. +

+

Example

+

+

+typedef list<int,char,long,short,char,long,double,long> types;
+

+BOOST_STATIC_ASSERT((count_if< types,boost::is_float<_> >::type::value == 1)); +BOOST_STATIC_ASSERT((count_if< types,boost::is_same<_,char> >::type::value == 2)); +BOOST_STATIC_ASSERT((count_if< types,boost::is_same<_,void> >::type::value == 0)); +

+

+

See also

+

+Algorithms, count, find_if, find, contains +


+Table of Content | Reference
Last edited July 17, 2002 4:32 am \ No newline at end of file diff --git a/doc/ref/Reference/distance.html b/doc/ref/Reference/distance.html new file mode 100644 index 0000000..18ca747 --- /dev/null +++ b/doc/ref/Reference/distance.html @@ -0,0 +1,56 @@ + +boost::mpl::Reference/distance + + +

[Home]distance

Synopsis

+

+

+template<
+      typename First
+    , typename Last
+    >
+struct distance
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Finds the distance between First and Last, that is, an Integral Constant D such as advance< First,D >::type is identical to Last. +

+

Definition

+

+

+#include "boost/mpl/distance.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
First, LastA model of Input Iterator
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef distance<First,Last>::type d;A model of Integral Constant[First, Last) is a valid rangeis_same< advance< First,d >::type, Last >::value
+

+

Complexity

+

+Amortized constant time if Iterator is a model of Random Access Iterator, otherwise linear time. +

+

Example

+

+

+typedef range_c<int,0,10>::type range;
+BOOST_STATIC_ASSERT((distance< begin<range>::type,end<range>::type >::type::value == 10));
+
+

+

See also

+

+Iterators, Sequence, advance, begin, end +


+Table of Content | Reference
Last edited July 17, 2002 6:47 am \ No newline at end of file diff --git a/doc/ref/Reference/divides.html b/doc/ref/Reference/divides.html new file mode 100644 index 0000000..9d4de2d --- /dev/null +++ b/doc/ref/Reference/divides.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/divides + + +

[Home]divides

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    , typaname T3 = integral_c<int,1>
+    , ...
+    , typaname Tn = integral_c<int,1>
+    >
+struct divides
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the quotient of its arguments [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/divides.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2, .., TnA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef divides<t1,t2,..,tn>::type quot;A model of Integral Constantt2::value != 0, t3::value != 0, .., tn::value != 0Equivalent to typedef integral_c<typeof(t1::value / t2::value .. / tn::value), t1::value / t2::value .. / tn::value > quot;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef divides< integral_c<short,-10>, integral_c<long,3> >::type quot;
+BOOST_STATIC_ASSERT(quot::value == -3));
+BOOST_MPL_ASSERT_IS_SAME(quot::value_type, long);
+
+

+

Notes

+

+[1] The divides metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, multiplies, modulus, plus, minus, negate +


+Table of Content | Reference
Last edited July 17, 2002 4:08 am \ No newline at end of file diff --git a/doc/ref/Reference/empty.html b/doc/ref/Reference/empty.html new file mode 100644 index 0000000..90e7347 --- /dev/null +++ b/doc/ref/Reference/empty.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/empty + + +

[Home]empty

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct empty
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns an Integral Constant c such that c::value == true if and only if the sequence is empty. +

+

Definition

+

+

+#include "boost/mpl/empty.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Sequence
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef empty<Sequence>::type c;A model of bool Integral ConstantEquivalent to typedef is_same< begin<Sequence>::type,end<Sequence>::type >::type c;
+

+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef range_c<int,0,0> empty_range;
+typedef list<long,float,double> types;
+

+BOOST_STATIC_ASSERT(empty<empty_range>::value) +BOOST_STATIC_ASSERT(!empty<types>::value) +

+

+

See also

+

+Sequence, size, begin, end +


+Table of Content | Reference
Last edited July 17, 2002 3:52 am \ No newline at end of file diff --git a/doc/ref/Reference/end.html b/doc/ref/Reference/end.html new file mode 100644 index 0000000..55e9c0d --- /dev/null +++ b/doc/ref/Reference/end.html @@ -0,0 +1,57 @@ + +boost::mpl::Reference/end + + +

[Home]end

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct end
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the past-the-end iterator to the sequence. +

+

Definition

+

+

+#include "boost/mpl/begin_end.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Sequence
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition  
typedef end<Sequence>::type last;A model of Input Iteratorlast is an iterator pointing one past the last element in the Sequence; equivalent to Sequence::end unless the algorithm has been specialized for the particular type of sequence.last is past-the-end.
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list<long> short_list;
+typedef begin<short_list>::type first;
+typedef end<short_list>::type last;
+BOOST_STATIC_ASSERT((boost::is_same<first::next,last>::value));
+
+

+

See also

+

+Iterators, Sequence, begin, size, empty +


+Table of Content | Reference
Last edited July 22, 2002 4:30 pm \ No newline at end of file diff --git a/doc/ref/Reference/equal.html b/doc/ref/Reference/equal.html new file mode 100644 index 0000000..9ea2cb8 --- /dev/null +++ b/doc/ref/Reference/equal.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/equal + + +

[Home]equal

Synopsis

+

+

+template<
+      typename Sequence1
+    , typename Sequence2
+    , typename Pred = is_same<_,_>
+    >
+struct equal
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if the two sequences Sequence1 and Sequence2 are identical when compared element-by-element, and otherwise returns false_c. +

+

Definition

+

+

+#include "boost/mpl/equal.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
Sequence1, Sequence2A model of Forward SequenceSequences to compare.
PredA binary Predicate [Lambda Expression]The comparison metafunction.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef equal<Sequence1,Sequence2,Pred>::type c;A model of Integral Constantc::value == true is and only if size<Sequence1>::type::value == size<Sequence2>::type::value and for every iterator i in [begin<Sequence>::type,end<Sequence>::type) i::type is identical to advance< begin<Sequence2>::type, distance< begin<Sequence1>::type,i >::type >::type.
+

+

Complexity

+

+Linear. At most size<Sequence1>::value comparisons. +

+

Example

+

+

+typedef vector<char,int,unsigned,long,unsigned long> s1;
+typedef list<char,int,unsigned,long,unsigned long> s2;
+BOOST_STATIC_ASSERT((equal<s1,s2>::type::value));
+
+

+

See also

+

+Algorithms, count, count_if +


+Table of Content | Reference
Last edited July 17, 2002 4:54 am \ No newline at end of file diff --git a/doc/ref/Reference/equal_to.html b/doc/ref/Reference/equal_to.html new file mode 100644 index 0000000..536f65d --- /dev/null +++ b/doc/ref/Reference/equal_to.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/equal to + + +

[Home]equal_to

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct equal_to
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value == T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/equal_to.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef equal_to<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value == t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,1,2,3,5,7,12,19,31> fibonacci;
+typedef find_if< fibonacci, equal_to<_,int_c<12> > >::type iter;
+BOOST_STATIC_ASSERT(equal_to< distance< begin<fibonacci>::type, iter >::type, int_c<5> >::type::value));
+
+

+

Notes

+

+[1] The equal_to metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, not_equal_to, less, less_equal, greater, greater_equal +


+Table of Content | Reference
Last edited July 17, 2002 4:13 am \ No newline at end of file diff --git a/doc/ref/Reference/erase.html b/doc/ref/Reference/erase.html new file mode 100644 index 0000000..dd72794 --- /dev/null +++ b/doc/ref/Reference/erase.html @@ -0,0 +1,65 @@ + +boost::mpl::Reference/erase + + +

[Home]erase

Synopsis

+

+

+template<
+      typename Sequence
+    , typename First
+    , typename Last = typename First::next
+    >
+struct erase
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+erase performs a removal of one or several consequent elements in the sequence starting from an arbitrary position. The algorithm returns a new sequence which contains all the elements in the ranges [begin<Sequence>::type, First) and [Last, end<Sequence>::type). The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/erase.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  Default value  
SequenceA model of Extensible SequenceA sequence to handle the erase operation.
FirstA model of Forward IteratorIterator to the beginning of the range to be erased.
LastA model of Forward IteratorPast-the-end iterator of the range to be erased.typename First::next
+

+

Expression semantics

+

+ + + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef erase<Sequence,pos>::type s;A model of Extensible Sequencepos is a dereferenceable iterator in Sequence.Returns a new sequence which contains all the elements in the ranges [begin<Sequence>::type, pos) and [next<pos>::type, end<Sequence>::type).size<s>::type::value == size<Sequence>::type::value - 1; the relative order of the elements in s is the same as in Sequence.
typedef erase<Sequence,first,last>::type s;A model of Extensible Sequence[first,last) is a valid range in Sequence.Returns a new sequence which contains all the elements in the ranges [begin<Sequence>::type, first) and [last, end<Sequence>::type).size<s>::type::value == size<Sequence>::type::value - distance<first,last>::type::value; the relative order of the elements in s is the same as in Sequence.
+

+

Complexity

+

+The range form has linear complexity. The complexity of single-element erase is sequence dependent (linear in the worst case, or amortized constant time). +

+

Example

+

+

+typedef list_c<int,1,0,5,1,7,5,0,5> values;
+typedef find< values, integral_c<int,7> >::type pos;
+typedef erase<values,pos>::type result_seq;
+BOOST_STATIC_ASSERT(size<result_seq>::type::value == 7);
+

+typedef find<result, integral_c<int,7> >::type result_iter; +BOOST_MPL_ASSERT_IS_SAME(result_iter, end<result_seq>::type); +

+

+

See also

+

+Extensible Sequence, pop_front, pop_back, insert +


+Table of Content | Reference
Last edited July 17, 2002 3:59 am \ No newline at end of file diff --git a/doc/ref/Reference/erase_all.html b/doc/ref/Reference/erase_all.html new file mode 100644 index 0000000..ceb8f67 --- /dev/null +++ b/doc/ref/Reference/erase_all.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/erase all + + +

[Home]erase_all

Synopsis +

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct erase_all
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/erase_all.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, erase, erase_if, erase_range +


+Table of Content | Reference
Last edited February 19, 2002 3:53 am \ No newline at end of file diff --git a/doc/ref/Reference/erase_if.html b/doc/ref/Reference/erase_if.html new file mode 100644 index 0000000..533901e --- /dev/null +++ b/doc/ref/Reference/erase_if.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/erase if + + +

[Home]erase_if

Synopsis +

+

+

+template<
+      typename Sequence
+    , typename Predicate
+    >
+struct erase_if
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/erase_if.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, erase_all, erase_if, erase_range +


+Table of Content | Reference
Last edited February 19, 2002 3:54 am \ No newline at end of file diff --git a/doc/ref/Reference/erase_range.html b/doc/ref/Reference/erase_range.html new file mode 100644 index 0000000..965ddb8 --- /dev/null +++ b/doc/ref/Reference/erase_range.html @@ -0,0 +1,63 @@ + +boost::mpl::Reference/erase range + + +

[Home]erase_range

Synopsis +

+

+

+template<
+      typename Sequence
+    , typename First
+    , typename Last
+    >
+struct erase_range
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/erase_range.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, erase, erase_all, erase_if +


+Table of Content | Reference
Last edited February 19, 2002 3:55 am \ No newline at end of file diff --git a/doc/ref/Reference/filter_view.html b/doc/ref/Reference/filter_view.html new file mode 100644 index 0000000..280f39b --- /dev/null +++ b/doc/ref/Reference/filter_view.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/filter view + + +

[Home]filter_view

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pred
+    >
+struct filter_view
+{
+};
+
+

+

Description

+

+filter_view is a sequence wrapper that allows one to operate on the filtered sequence without actually creating one. +

+

Definition

+

+

+#include "boost/mpl/filter_view.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to wrap.
PredA model of unary Predicate [Lambda Expression]A filtering predicate.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef filter_view<Sequence,Pred> s;A model of Sequences prodives iterators to all the elements in the range [begin<Sequence>::type,end<Sequence>::type) that satisfy the predicate Pred.size<s>::type::value == count_if< Sequence,Pred >::type::value.
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+Finds the largest floating type in a sequence. +

+

+typedef list<int,float,long,float,char[50],long double,char> types;
+typedef max_element<
+      transform_view< filter_view< types,boost::is_float<_> >, size_of<_> >
+    >::type iter;
+

+BOOST_STATIC_ASSERT((is_same<iter::base::type,long double>::value)); +

+

+

See also

+

+Sequences, transform_view, list, max_element +


+Table of Content | Reference
Last edited July 23, 2002 4:04 am \ No newline at end of file diff --git a/doc/ref/Reference/find.html b/doc/ref/Reference/find.html new file mode 100644 index 0000000..20384f2 --- /dev/null +++ b/doc/ref/Reference/find.html @@ -0,0 +1,58 @@ + +boost::mpl::Reference/find + + +

[Home]find

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct find
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Finds the first occurrence of type T in a Sequence. +

+

Definition

+

+

+#include "boost/mpl/find.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to search in.
TA typeThe type to search for.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef find<Sequence,T>::type i;A model of Forward IteratorEquivalent to typedef find_if<Sequence, is_same<_,T> >::type i;
+

+

Complexity

+

+Linear. At most size<Sequence>::value comparisons for identity. +

+

Example

+

+

+typedef vector<char,int,unsigned,long,unsigned long> types;
+typedef find<types,unsigned>::type iter;
+BOOST_STATIC_ASSERT(iter::position == 2);
+
+

+

See also

+

+Algorithms, find_if, contains, count, count_if +


+Table of Content | Reference
Last edited July 17, 2002 4:48 am \ No newline at end of file diff --git a/doc/ref/Reference/find_if.html b/doc/ref/Reference/find_if.html new file mode 100644 index 0000000..3b690dc --- /dev/null +++ b/doc/ref/Reference/find_if.html @@ -0,0 +1,58 @@ + +boost::mpl::Reference/find if + + +

[Home]find_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pred
+    >
+struct find_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Finds the first element in a Sequence that satisfies the predicate Pred. +

+

Definition

+

+

+#include "boost/mpl/find_if.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to search in.
PredA model of Predicate [Lambda Expression]A search condition.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef find_if<Sequence,Pred>::type i;A model of Forward Iteratori is the first iterator in the range [begin<Sequence>::type, end<Sequence>::type) such that apply< lambda<Pred>::type,i::type >::type::value == true; i is identical to end<Sequence>::type, if no such iterator exists.
+

+

Complexity

+

+Linear. At most size<Sequence>::value applications of Pred. +

+

Example

+

+

+typedef vector<char,int,unsigned,long,unsigned_long> types;
+typedef find_if<types, is_same<_1,unsigned> >::type iter;
+BOOST_STATIC_ASSERT(iter::position == 2);
+
+

+

See also

+

+Algorithms, find, contains, count, count_if +


+Table of Content | Reference
Last edited July 17, 2002 4:48 am \ No newline at end of file diff --git a/doc/ref/Reference/fold.html b/doc/ref/Reference/fold.html new file mode 100644 index 0000000..ee2368d --- /dev/null +++ b/doc/ref/Reference/fold.html @@ -0,0 +1,65 @@ + +boost::mpl::Reference/fold + + +

[Home]fold

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename ForwardOp
+    >
+struct fold
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of binary ForwardOp to the result of the previous ForwardOp invocation (State if it's the first call) and every element of the sequence in the range [begin<Sequence>::type,end<Sequence>::type) in the linear order. +

+

Definition

+

+

+#include "boost/mpl/fold.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first ForwardOp application.
ForwardOpA model of [Lambda Function]The operation to be executed on forward traversal.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef fold<Sequence,T,Op>::type t;A typeEquivalent to typedef lambda<Op>::type op; typedef iter_fold< Sequence,T,apply<op,_1,deref<_2> > >::type t;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of ForwardOp. +

+

Example

+

+

+typedef vector<long,float,short,double,float,long,long double> types;
+typedef typename fold<
+      types
+    , integral_c<long, 0>
+    , if_< is_float<_2>,next<_1>,_1 >
+    >::type number_of_floats;
+

+BOOST_STATIC_ASSERT(number_of_floats::value == 3); +

+

+

See also

+

+Algorithms, fold_backward, iter_fold, iter_fold_backward, copy, copy_if +


+Table of Content | Reference
Last edited July 19, 2002 2:12 am \ No newline at end of file diff --git a/doc/ref/Reference/fold_backward.html b/doc/ref/Reference/fold_backward.html new file mode 100644 index 0000000..c192da7 --- /dev/null +++ b/doc/ref/Reference/fold_backward.html @@ -0,0 +1,75 @@ + +boost::mpl::Reference/fold backward + + +

[Home]fold_backward

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BackwardOp
+    , typename ForwardOp = _1
+    >
+struct fold_backward
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of binary BackwardOp to the result of the previous BackwardOp invocation (State if it's the first call) and every element in the range [begin<Sequence>::type,end<Sequence>::type) in the reverse order. If ForwardOp is provided, then it's applied on forward traversal to form the result which is passed to the first BackwardOp call. +

+

Definition

+

+

+#include "boost/mpl/fold_backward.hpp"
+
+

+

Parameters

+ + + + + + +
 Parameter  Requirement  Description  Default value  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BackwardOp/ForwardOp application.
BackwardOpA model of [Lambda Function]The operation to be executed on backward traversal.
ForwardOpA model of [Lambda Function]The operation to be executed on forward traversal.arg<1>
+

+

Expression semantics

+

+ + + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef fold_backward< Sequence,T,BackwardOp >::type t;A typeEquivalent to typedef lambda<BackwardOp>::type bk_op; typedef begin<Sequence>::type i1; typedef i1::next i2; ...; typedef in::next last; typedef apply<bk_op,T,in::type>::type tn; typedef apply<bk_op,tn,in-1::type>::type tn-1; ...; typedef apply<bk_op,t2,i1::type>::type t1; typedef t1 t, where n == size<Sequence>::type::value and last is identical to end<Sequence>::type; Equivalent to typedef T t; if the sequence is empty.
typedef fold_backward< Sequence,T,BackwardOp,ForwardOp >::type t;A typeEquivalent to typedef fold_backward<Sequence, fold<Sequence,State,ForwardOp>::type, BackwardOp>::type t;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of BackwardOp and ForwardOp. +

+

Example

+

+Removes negative elements from a sequence [1]. +

+

+typedef list_c<int,5,-1,0,-7,-2,0,-5,4> numbers;
+typedef list_c<int,-1,-7,-2,-5> negatives;
+typedef fold_backward<
+      numbers
+    , list_c<int>
+    , if_< less< _2,int_c<0> >, push_front<_1,_2,>, _1 >
+    >::type result;
+

+BOOST_STATIC_ASSERT(equal< negatives,result,equal_to<_,_> >::type::value); +

+

+

Notes

+

+[1] See remove_if for a more compact way to do this.
+

+

See also

+

+Algorithms, fold, iter_fold_backward, iter_fold, copy, copy_backward +


+Table of Content | Reference
Last edited July 19, 2002 1:58 am \ No newline at end of file diff --git a/doc/ref/Reference/front.html b/doc/ref/Reference/front.html new file mode 100644 index 0000000..056cc3f --- /dev/null +++ b/doc/ref/Reference/front.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/front + + +

[Home]front

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct front
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a type identical to the first element in the sequence. +

+

Definition

+

+

+#include "boost/mpl/front.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sequence to be examined.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef front<Sequence>::type t;A typeempty<Sequence>::type::value == falseEquivalent to typedef begin<Sequence>::type::type t;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list<long>::type types1;
+typedef list<int,long>::type types2;
+typedef list<char,int,long>::type types3;
+

+BOOST_MPL_ASSERT_IS_SAME(front<types1>::type, long); +BOOST_MPL_ASSERT_IS_SAME(front<types2>::type, int); +BOOST_MPL_ASSERT_IS_SAME(front<types3>::type, char); +

+

+

See also

+

+Forward Sequence, back, at, push_front, begin, empty +


+Table of Content | Reference
Last edited July 17, 2002 3:48 am \ No newline at end of file diff --git a/doc/ref/Reference/greater.html b/doc/ref/Reference/greater.html new file mode 100644 index 0000000..81292ed --- /dev/null +++ b/doc/ref/Reference/greater.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/greater + + +

[Home]greater

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct greater
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value > T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/greater.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef greater<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value > t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,1,2,3,5,7,12,19,31> fibonacci;
+typedef find_if< fibonacci, greater<_,int_c<10> > >::type iter;
+BOOST_STATIC_ASSERT(iter::type::value == 12));
+
+

+

Notes

+

+[1] The greater metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, greater_equal, less, less_equal, equal_to, not_equal_to +


+Table of Content | Reference
Last edited July 17, 2002 4:16 am \ No newline at end of file diff --git a/doc/ref/Reference/greater_equal.html b/doc/ref/Reference/greater_equal.html new file mode 100644 index 0000000..3f0ee12 --- /dev/null +++ b/doc/ref/Reference/greater_equal.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/greater equal + + +

[Home]greater_equal

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct greater_equal
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value > T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/greater_equal.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef greater_equal<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value >= t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,0,1,2,3,4,5,6,7,8,9> numbers;
+typedef remove_if< numbers, greater_equal<_,int_c<5> > >::type result;
+BOOST_STATIC_ASSERT(equal< result,range_c<int,0,5>,equal_to<_,_> >::type::value));
+
+

+

Notes

+

+[1] The greater_equal metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, greater, less, less_equal, equal_to, not_equal_to +


+Table of Content | Reference
Last edited July 17, 2002 4:16 am \ No newline at end of file diff --git a/doc/ref/Reference/insert.html b/doc/ref/Reference/insert.html new file mode 100644 index 0000000..63f6554 --- /dev/null +++ b/doc/ref/Reference/insert.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/insert + + +

[Home]insert

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pos
+    , typename T
+    >
+struct insert
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+insert performs an insertion of type T at an arbitrary position in the sequence. The algorithm returns a new sequence which contains all the elements from Sequence plus the type T at the distance< begin<Sequence>::type,Pos >::type position from the beginning. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/insert.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the insert operation.
PosA model of Forward IteratorAn insert position in the Sequence.
TA typeThe element to be inserted.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef insert<Sequence,pos,T>::type s;A model of Extensible Sequencepos is a valid iterator in Sequence.s contains T at the distance< begin<Sequence>::type,pos >::type position.size<s>::type::value == size<Sequence>::type::value + 1; at< distance< begin<Sequence>::type,pos >::type, s >::type is identical to T; the relative order of the elements in s is the same as in Sequence.
+

+

Complexity

+

+Sequence dependent. Linear in the worst case, or amortized constant time. +

+

Example

+

+

+typedef list_c<int,0,1,3,4,5,6,7,8,9> numbers;
+typedef find< numbers,integral_c<int,3> >::type pos;
+typedef insert< numbers,pos,integral_c<int,2> >::type range;
+BOOST_STATIC_ASSERT(size<range>::type::value == 10);
+BOOST_STATIC_ASSERT((equal< range,range_c<int,0,10> >::type::value));
+
+

+

See also

+

+Extensible Sequence, insert_range, push_front, push_back, erase +


+Table of Content | Reference
Last edited July 17, 2002 5:17 am \ No newline at end of file diff --git a/doc/ref/Reference/insert_range.html b/doc/ref/Reference/insert_range.html new file mode 100644 index 0000000..f7a8672 --- /dev/null +++ b/doc/ref/Reference/insert_range.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/insert range + + +

[Home]insert_range

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pos
+    , typename Range
+    >
+struct insert_range
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+insert_range performs an insertion of a range of elements at an arbitrary position in the sequence. The algorithm returns a new sequence which contains all the elements of Sequence plus all the elements of Range starting at the distance< begin<Sequence>::type,Pos >::type position from the beginning. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/insert_range.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the insert operation.
PosA model of Forward IteratorAn insert position in the Sequence.
RangeA model of SequenceThe range of elements to be inserted.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition  
typedef insert<Sequence,pos,range>::type s;A model of Extensible Sequencepos is a valid iterator in Sequence.s contains all the elements from range starting at the distance< begin<Sequence>::type,pos >::type position.size<s>::type::value == size<Sequence>::type::value + size<range>::type::value; the relative order of the elements in s is the same as in Sequence.
+

+

Complexity

+

+Linear time. +

+

Example

+

+

+typedef list_c<int,0,1,7,8,9> numbers;
+typedef find< numbers,integral_c<int,7> >::type pos;
+typedef insert_range< numbers,pos,range_c<int,2,7> >::type range;
+BOOST_STATIC_ASSERT(size<range>::type::value == 10);
+BOOST_STATIC_ASSERT((equal< range,range_c<int,0,10> >::type::value));
+
+

+

See also

+

+Extensible Sequence, insert, push_front, push_back, erase +


+Table of Content | Reference
Last edited July 22, 2002 4:32 pm \ No newline at end of file diff --git a/doc/ref/Reference/iter_fold.html b/doc/ref/Reference/iter_fold.html new file mode 100644 index 0000000..b336eb1 --- /dev/null +++ b/doc/ref/Reference/iter_fold.html @@ -0,0 +1,65 @@ + +boost::mpl::Reference/iter fold + + +

[Home]iter_fold

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename ForwardOp
+    >
+struct iter_fold
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of binary ForwardOp to the result of the previous ForwardOp invocation (State if it's the first call) and each iterator in the range [begin<Sequence>::type,end<Sequence>::type) in the linear order. +

+

Definition

+

+

+#include "boost/mpl/iter_fold.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first ForwardOp application.
ForwardOpA model of [Lambda Function]The operation to be executed on forward traversal.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef iter_fold<Sequence,T,Op>::type t;A typeEquivalent to typedef lambda<Op>::type op; typedef begin<Sequence>::type i1; typedef apply<op,T,i1>::type t1; typedef i1::next i2; typedef apply<op,t1,i2>::type t2; ...; typedef apply<op,T,in>::type tn; typedef in::next last; typedef tn t, where n == size<Sequence>::type::value and last is identical to end<Sequence>::type; Equivalent to typedef T t; if the sequence is empty.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of ForwardOp. +

+

Example

+

+

+typedef list_c<int,5,-1,0,7,2,0,-5,4> numbers;
+typedef iter_fold<
+      numbers
+    , begin<numbers>::type
+    , if_< less< deref<_1>, deref<_2> >,_2,_1 >
+    >::type max_element_iter;
+

+BOOST_STATIC_ASSERT(max_element_iter::type::value == 7); +

+

+

See also

+

+Algorithms, iter_fold_backward, fold, fold_backward, copy, copy_backward +


+Table of Content | Reference
Last edited July 19, 2002 1:16 am \ No newline at end of file diff --git a/doc/ref/Reference/iter_fold_backward.html b/doc/ref/Reference/iter_fold_backward.html new file mode 100644 index 0000000..a2b7b3a --- /dev/null +++ b/doc/ref/Reference/iter_fold_backward.html @@ -0,0 +1,71 @@ + +boost::mpl::Reference/iter fold backward + + +

[Home]iter_fold_backward

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BackwardOp
+    , typename ForwardOp = _1
+    >
+struct iter_fold_backward
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of binary BackwardOp to the result of the previous BackwardOp invocation (State if it's the first call) and each iterator in the range [begin<Sequence>::type,end<Sequence>::type) in the reverse order. If ForwardOp is provided, then it's applied on forward traversal to form the result which is passed to the first BackwardOp call. +

+

Definition

+

+

+#include "boost/mpl/iter_fold_backward.hpp"
+
+

+

Parameters

+ + + + + + +
 Parameter  Requirement  Description  Default value  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BackwardOp/ForwardOp application.
BackwardOpA model of [Lambda Function]The operation to be executed on backward traversal.
ForwardOpA model of [Lambda Function]The operation to be executed on forward traversal.arg<1>
+

+

Expression semantics

+

+ + + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef iter_fold_backward< Sequence,T,BackwardOp >::type t;A typeEquivalent to typedef lambda<BackwardOp>::type bk_op; typedef begin<Sequence>::type i1; typedef i1::next i2; ...; typedef in::next last; typedef apply<bk_op,T,in>::type tn; typedef apply<bk_op,tn,in-1>::type tn-1; ...; typedef apply<bk_op,t2,i1>::type t1; typedef t1 t, where n == size<Sequence>::type::value and last is identical to end<Sequence>::type; Equivalent to typedef T t; if the sequence is empty.
typedef iter_fold_backward< Sequence,T,BackwardOp,ForwardOp >::type t;A typeEquivalent to typedef iter_fold_backward<Sequence, iter_fold<Sequence,State,ForwardOp>::type, BackwardOp>::type t;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of BackwardOp and ForwardOp. +

+

Example

+

+Builds a list of iterators to the negative elements in a sequence. +

+

+typedef vector_c<int,5,-1,0,-7,-2,0,-5,4> numbers;
+typedef list_c<int,-1,-7,-2,-5> negatives;
+typedef iter_fold_backward<
+      numbers
+    , list<>
+    , if_< less< deref<_2>,int_c<0> >, push_front<_1,_2>, _1 >
+    >::type iters;
+

+BOOST_STATIC_ASSERT(equal< negatives, transform_view< iters,deref<_> >, equal_to<_,_> >::type::value); +

+

+

See also

+

+Algorithms, iter_fold, fold_backward, fold, copy, copy_backward +


+Table of Content | Reference
Last edited July 19, 2002 1:58 am \ No newline at end of file diff --git a/doc/ref/Reference/iter_fold_if.html b/doc/ref/Reference/iter_fold_if.html new file mode 100644 index 0000000..320c43f --- /dev/null +++ b/doc/ref/Reference/iter_fold_if.html @@ -0,0 +1,70 @@ + +boost::mpl::Reference/iter fold if + + +

[Home]iter_fold_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename State
+    , typename BackwardOp
+    , typename ForwardOp = _1
+    >
+struct iter_fold_backward
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of the successive application of binary BackwardOp to the result of the previous BackwardOp invocation (State if it's the first call) and each iterator in the range [begin<Sequence>::type,end<Sequence>::type) in the reverse order. If ForwardOp is provided, then it's applied on forward traversal to form the result which is passed to the first BackwardOp call. +

+

Definition

+

+

+#include "boost/mpl/iter_fold_backward.hpp"
+
+

+

Parameters

+ + + + + + +
 Parameter  Requirement  Description  Default value  
SequenceA model of SequenceA sequence to iterate.
StateA typeThe initial state for the first BackwardOp/ForwardOp application.
BackwardOpA model of [Lambda Function]The operation to be executed on backward traversal.
ForwardOpA model of [Lambda Function]The operation to be executed on forward traversal.arg<1>
+

+

Expression semantics

+

+ + + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef iter_fold_backward< Sequence,T,BackwardOp >::type t;A typeEquivalent to typedef lambda<BackwardOp>::type bk_op; typedef begin<Sequence>::type i1; typedef i1::next i2; ...; typedef in::next last; typedef apply<bk_op,T,in>::type tn; typedef apply<bk_op,tn,in-1>::type tn-1; ...; typedef apply<bk_op,t2,i1>::type t1; typedef t1 t, where n == size<Sequence>::type::value and last is identical to end<Sequence>::type; Equivalent to typedef T t; if the sequence is empty.
typedef iter_fold_backward< Sequence,T,BackwardOp,ForwardOp >::type t;A typeEquivalent to typedef iter_fold_backward<Sequence, iter_fold<Sequence,State,ForwardOp>::type, BackwardOp>::type t;.
+

+

Complexity

+

+Linear. Exactly size<Sequence>::type::value applications of BackwardOp and ForwardOp. +

+

Example

+

+Finds an iterator to the last negative element in the sequence. +

+

+typedef list_c<int,5,-1,0,7,2,0,-5,4> numbers;
+typedef iter_fold_backward<
+      numbers
+    , end<numbers>::type
+    , if_< less< deref<_2>, int_c<0> >,_2,_1 >
+    >::type last_negative_iter;
+

+BOOST_STATIC_ASSERT(last_negative_iter::type::value == -5); +

+

+

See also

+

+Algorithms, iter_fold, fold_backward, fold, copy, copy_backward +


+Table of Content | Reference
Last edited July 19, 2002 1:25 am \ No newline at end of file diff --git a/doc/ref/Reference/iterator_category.html b/doc/ref/Reference/iterator_category.html new file mode 100644 index 0000000..904dd4e --- /dev/null +++ b/doc/ref/Reference/iterator_category.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/iterator category + + +

[Home]iterator_category

Synopsis

+

+

+template<
+      typename Iterator
+    >
+struct iterator_category
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns one of the following iterator category tags: input_iterator_tag, forward_iterator_tag, bidirectional_iterator_tag, or random_access_iterator_tag. +

+

Definition

+

+

+#include "boost/mpl/iterator_category.hpp"
+#include "boost/mpl/iterator_tag.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
IteratorA model of Input Iterator
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition  
typedef iterator_category<Iterator>::type tag;An iterator category tagtag is input_iterator_tag if Iterator is a model of Input Iterator, forward_iterator_tag if Iterator is a model of Forward Iterator, bidirectional_iterator_tag if Iterator is a model of Bidirectional Iterator, or random_access_iterator_tag if Iterator is a model of Random Access Iterator.
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+template< typename Iterator >
+struct my_algorithm
+    : my_algorithm_impl<
+          iterator_category<Iterator>::type
+        , Iterator
+        >
+{
+};
+
+

+

See also

+

+Iterators, Sequence, begin, end, advance, distance +


+Table of Content | Reference
Last edited July 17, 2002 6:20 am \ No newline at end of file diff --git a/doc/ref/Reference/less.html b/doc/ref/Reference/less.html new file mode 100644 index 0000000..a8aa5e8 --- /dev/null +++ b/doc/ref/Reference/less.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/less + + +

[Home]less

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct less
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value < T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/less.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef less<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value < t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,0,1,2,3,4,5,6,7,8,9> numbers;
+typedef remove_if< numbers, less<_,int_c<5> > >::type result;
+BOOST_STATIC_ASSERT(equal< result,range_c<int,5,10>,equal_to<_,_> >::type::value));
+
+

+

Notes

+

+[1] The less metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, less_equal, greater, greater_equal, equal, not_equal_to +


+Table of Content | Reference
Last edited July 17, 2002 4:15 am \ No newline at end of file diff --git a/doc/ref/Reference/less_equal.html b/doc/ref/Reference/less_equal.html new file mode 100644 index 0000000..e1293f6 --- /dev/null +++ b/doc/ref/Reference/less_equal.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/less equal + + +

[Home]less_equal

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct less_equal
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value <= T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/less_equal.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef less_equal<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value <= t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,0,1,2,3,4,5,6,7,8,9> numbers;
+typedef remove_if< numbers, less_equal<_,int_c<4> > >::type result;
+BOOST_STATIC_ASSERT(equal< result,range_c<int,5,10>,equal_to<_,_> >::type::value));
+
+

+

Notes

+

+[1] The less_equal metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, less, greater, greater_equal, equal, not_equal_to +


+Table of Content | Reference
Last edited July 17, 2002 4:15 am \ No newline at end of file diff --git a/doc/ref/Reference/list.html b/doc/ref/Reference/list.html new file mode 100644 index 0000000..6bf9629 --- /dev/null +++ b/doc/ref/Reference/list.html @@ -0,0 +1,45 @@ + +boost::mpl::Reference/list + + +

[Home]list

Synopsis

+

+

+template<
+      typename T1 = implementation-defined
+    , typename T2 = implementation-defined
+    , ...
+    , typename Tn = implementation-defined
+    >
+struct list
+{
+};
+
+

+

Description

+

+A list is a Forward Sequence of types. It's also an Extensible Sequence that supports constant time insertion and removal of elements at the beginning (through push_front), and linear time insertion and removal of elements at the end or in the middle (through insert/erase algorithms). +

+

Example

+

+

+typedef list<float,double,long double> floats;
+typedef push_front<floating_types,my_float>::type ext_floats;
+BOOST_STATIC_ASSERT((boost::is_same< front<ext_floats>::type, my_float >::value));
+
+

+

Definition

+

+

+#include "boost/mpl/list.hpp"
+#include "boost/mpl/list/list0.hpp"
+#include "boost/mpl/list/list10.hpp"
+...
+#include "boost/mpl/list/list50.hpp"
+
+

+

See also

+

+Forward Sequence, list_c, vector, vector_c, range_c +


+Table of Content | Reference
Last edited July 17, 2002 8:05 am \ No newline at end of file diff --git a/doc/ref/Reference/list_c.html b/doc/ref/Reference/list_c.html new file mode 100644 index 0000000..b98a9a7 --- /dev/null +++ b/doc/ref/Reference/list_c.html @@ -0,0 +1,58 @@ + +boost::mpl::Reference/list c + + +

[Home]list_c

Synopsis

+

+

+template<
+      typename T
+    , T C1 = implementation-defined
+    , T C2 = implementation-defined
+    , ...
+    , T CN = implementation-defined
+    >
+struct list_c
+{
+};
+
+

+

Description

+

+Similary to vector_c, list_c is a shorcut interface whose whole purpose is to make the creation of a list of Integral Constants less verbose: +

+

+typedef list_c<unsigned long,-1,0,1,1,-1,0,0,1,-1> data;
+
+

+If list_c didn't exist, instead of the above line you would have to write this: +

+

+typedef list<
+      integral_c<unsigned long,-1>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,-1>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,-1>
+    > data;
+
+

+

Definition

+

+

+#include "boost/mpl/list_c.hpp"
+#include "boost/mpl/list/list0_c.hpp"
+#include "boost/mpl/list/list10_c.hpp"
+...
+#include "boost/mpl/list/list50_c.hpp"
+
+

+

See also

+

+Random Access Sequence, list, vector, vector_c, range_c +


+Table of Content | Reference
Last edited July 17, 2002 8:04 am \ No newline at end of file diff --git a/doc/ref/Reference/logical_and.html b/doc/ref/Reference/logical_and.html new file mode 100644 index 0000000..ce03f3d --- /dev/null +++ b/doc/ref/Reference/logical_and.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/logical and + + +

[Home]logical_and

Synopsis

+

+

+template< 
+      typename F1
+    , typename F2
+    , typename F3 = true_c
+    ...
+    , typename Fn = true_c
+    >
+struct logical_and
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of short-circuit logical and (&&) operation on its arguments. +

+

Definition

+

+

+#include "boost/mpl/logical/and.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
F1, F2, .., FnA model of nullary Metafunction
+

+

Expression semantics

+

+ + + +
 Expression  Precondition  Semantics  Postcondition 
typedef logical_and<f1,f2,..,fn>::type c;Returns false_c if either of f1::type::value, f2::type::value, .., fn::type::value expressions evaluates to false, and true_c otherwise; guarantees left-to-right evaluation; moreover, the operands subsequent to the first fi metafunction that evaluates to false are not evaluated.
+

+

Example

+

+

+// will generate compile-time error if invoked with T == any fundamental type
+template< typename T > struct fail
+{
+   typedef typename T::nonexistent type;
+};
+

+BOOST_STATIC_ASSERT((logical_and< true_c,false_c >::type::value == false)); +BOOST_STATIC_ASSERT((logical_and< false_c,fail<int> >::type::value == false)); // ok, fail<int> is never invoked +BOOST_STATIC_ASSERT((logical_and< true_c,false_c,fail<int> >::type::value == false)); // ok too +

+

+

See also

+

+Metafunctions, logical_or, logical_not +


+Table of Content | Reference
Last edited July 17, 2002 1:06 am \ No newline at end of file diff --git a/doc/ref/Reference/logical_not.html b/doc/ref/Reference/logical_not.html new file mode 100644 index 0000000..bc47337 --- /dev/null +++ b/doc/ref/Reference/logical_not.html @@ -0,0 +1,51 @@ + +boost::mpl::Reference/logical not + + +

[Home]logical_not

Synopsis

+

+

+template< 
+      typename F
+    >
+struct logical_not
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of logical not (!) operation on its argument. +

+

Definition

+

+

+#include "boost/mpl/logical/not.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
FA model of nullary Metafunction
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef logical_not<f>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(!f::type::value)> c;
+

+

Example

+

+

+BOOST_STATIC_ASSERT(logical_not<true_c>::type::value == false);
+BOOST_STATIC_ASSERT(logical_not<false_c>::type::value == true);
+
+

+

See also

+

+Metafunctions, logical_and, logical_or +


+Table of Content | Reference
Last edited July 17, 2002 4:13 am \ No newline at end of file diff --git a/doc/ref/Reference/logical_or.html b/doc/ref/Reference/logical_or.html new file mode 100644 index 0000000..801007d --- /dev/null +++ b/doc/ref/Reference/logical_or.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/logical or + + +

[Home]logical_or

Synopsis

+

+

+template< 
+      typename F1
+    , typename F2
+    , typename F3 = false_c
+    ...
+    , typename Fn = false_c
+    >
+struct logical_or
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the result of short-circuit logical or (||) operation on its arguments. +

+

Definition

+

+

+#include "boost/mpl/logical/or.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
F1, F2, .., FnA model of nullary Metafunction
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef logical_or<f1,f2,..,fn>::type c;A model of bool Integral ConstantReturns true_c if either of f1::type::value, f2::type::value, .., fn::type::value expressions evaluates to true, and false_c otherwise; guarantees left-to-right evaluation; moreover, the operands subsequent to the first fi metafunction that evaluates to true are not evaluated.
+

+

Example

+

+

+// will generate compile-time error if invoked with T == any fundamental type
+template< typename T > struct fail
+{
+   typedef typename T::nonexistent type;
+};
+

+BOOST_STATIC_ASSERT((logical_or< false_c,true_c >::type::value == true)); +BOOST_STATIC_ASSERT((logical_or< true_c,fail<int> >::type::value == true)); // ok, fail<int> is never invoked +BOOST_STATIC_ASSERT((logical_or< false_c,true_c,fail<int> >::type::value == true)); // ok too +

+

+

See also

+

+Metafunctions, logical_and, logical_not +


+Table of Content | Reference
Last edited July 17, 2002 4:12 am \ No newline at end of file diff --git a/doc/ref/Reference/lower_bound.html b/doc/ref/Reference/lower_bound.html new file mode 100644 index 0000000..0b116d4 --- /dev/null +++ b/doc/ref/Reference/lower_bound.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/lower bound + + +

[Home]lower_bound

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    , typename Pred
+    >
+struct lower_bound
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the first position in the sorted Sequence where T could be inserted without violating the ordering. +

+

Definition

+

+

+#include "boost/mpl/lower_bound.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sorted sequence.
TA typeA type to search the position for.
PredA model of binary Predicate [Lambda Expression]A sort criteria.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef lower_bound< Sequence,T,Pred >::type i;A model of Forward Iteratori is the furthermost iterator in [begin<Sequence>::type, end<Sequence>::type) such that, for every iterator j in [begin<Sequence>::type, i), apply< lambda<Pred>::type, j::type, T >::type::value == true.
+

+

Complexity

+

+The number of comparisons is logarithmic: at most log(size<Sequence>::type::value) + 1. If Sequence is a Random Access Sequence then the number of steps through the range is also logarithmic; otherwise, the number of steps is proportional to size<Sequence>::type::value. +

+

Example

+

+

+typedef list_c<int,1,2,3,3,3,5,8> numbers;
+typedef lower_bound< numbers, int_c<3>, less<_,_> >::type iter;
+BOOST_STATIC_ASSERT((distance< begin<numbers>::type,iter >::type::value == 2));
+
+

+

See also

+

+Algorithms, sort, upper_bound +


+Table of Content | Reference
Last edited July 17, 2002 5:13 am \ No newline at end of file diff --git a/doc/ref/Reference/minus.html b/doc/ref/Reference/minus.html new file mode 100644 index 0000000..1910713 --- /dev/null +++ b/doc/ref/Reference/minus.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/minus + + +

[Home]minus

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    , typaname T3 = integral_c<int,0>
+    , ...
+    , typaname Tn = integral_c<int,0>
+    >
+struct minus
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the difference of its arguments [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/minus.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2, .., TnA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef minus<t1,t2,..,tn>::type diff;A model of Integral ConstantEquivalent to typedef integral_c<typeof(t1::value - t2::value .. - tn::value), t1::value - t2::value .. - tn::value > diff;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef minus< integral_c<short,-1>, integral_c<long,10> >::type diff;
+BOOST_STATIC_ASSERT(diff::value == -11));
+BOOST_MPL_ASSERT_IS_SAME(diff::value_type, long);
+
+

+

Notes

+

+[1] The minus metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, plus, divides, multiplies, modulus, negate +


+Table of Content | Reference
Last edited July 17, 2002 4:06 am \ No newline at end of file diff --git a/doc/ref/Reference/modulus.html b/doc/ref/Reference/modulus.html new file mode 100644 index 0000000..0f39fb7 --- /dev/null +++ b/doc/ref/Reference/modulus.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/modulus + + +

[Home]modulus

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct modulus
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the modulus of its arguments [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/modulus.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef modulus<t1,t2>::type mod;A model of Integral Constantt2::value != 0 Equivalent to typedef integral_c<typeof(t1::value % t2::value), t1::value % t2::value> mod;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef modulus< integral_c<short,10>, integral_c<long,3> >::type mod;
+BOOST_STATIC_ASSERT(mod::value == 1));
+BOOST_MPL_ASSERT_IS_SAME(mod::value_type, long);
+
+

+

Notes

+

+[1] The modulus metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, divides, multiplies, plus, minus, negate +


+Table of Content | Reference
Last edited July 17, 2002 4:10 am \ No newline at end of file diff --git a/doc/ref/Reference/multiplies.html b/doc/ref/Reference/multiplies.html new file mode 100644 index 0000000..9a00ea3 --- /dev/null +++ b/doc/ref/Reference/multiplies.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/multiplies + + +

[Home]multiplies

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    , typaname T3 = integral_c<int,1>
+    , ...
+    , typaname Tn = integral_c<int,1>
+    >
+struct multiplies
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the product of its arguments [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/multiplies.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2, .., TnA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef multiplies<t1,t2,..,tn>::type product;A model of Integral ConstantEquivalent to typedef integral_c<typeof(t1::value * t2::value .. * tn::value), t1::value * t2::value .. * tn::value > product;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef multiplies< integral_c<short,-1>, integral_c<long,10> >::type product;
+BOOST_STATIC_ASSERT(product::value == -10));
+BOOST_MPL_ASSERT_IS_SAME(product::value_type, long);
+
+

+

Notes

+

+[1] The multiplies metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, divides, modulus, plus, minus, negate +


+Table of Content | Reference
Last edited July 17, 2002 4:07 am \ No newline at end of file diff --git a/doc/ref/Reference/negate.html b/doc/ref/Reference/negate.html new file mode 100644 index 0000000..0b57a14 --- /dev/null +++ b/doc/ref/Reference/negate.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/negate + + +

[Home]negate

Synopsis

+

+

+template<
+      typename T
+    >
+struct negate
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the negative (additive inverse) of its argument [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/negate.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
TA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef negate<t>::type n;A model of Integral ConstantEquivalent to typedef integral_c<t::value_type, -t::value> n;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef negate< integral_c<short,-10> >::type n;
+BOOST_STATIC_ASSERT(n::value == 10));
+BOOST_MPL_ASSERT_IS_SAME(n::value_type, short);
+
+

+

Notes

+

+[1] The negate metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, minus, plus, multiplies, divides, modulus +


+Table of Content | Reference
Last edited July 17, 2002 4:10 am \ No newline at end of file diff --git a/doc/ref/Reference/next.html b/doc/ref/Reference/next.html new file mode 100644 index 0000000..cc00727 --- /dev/null +++ b/doc/ref/Reference/next.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/next + + +

[Home]next

Synopsis +

+

+

+template<
+      typename T
+    >
+struct next
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/next.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, prior +


+Table of Content | Reference
Last edited February 19, 2002 4:25 am \ No newline at end of file diff --git a/doc/ref/Reference/not_equal_to.html b/doc/ref/Reference/not_equal_to.html new file mode 100644 index 0000000..785e28a --- /dev/null +++ b/doc/ref/Reference/not_equal_to.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/not equal to + + +

[Home]not_equal_to

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    >
+struct not_equal_to
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns true_c if T1::value != T2::value and false_c otherwise [1]. +

+

Definition

+

+

+#include "boost/mpl/comparison/not_equal_to.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2A model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef not_equal_to<t1,t2>::type c;A model of bool Integral ConstantEquivalent to typedef bool_c<(t1::value != t2::value)> c;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef list_c<int,1,5,0,7,5,-1,2,4,5> numbers;
+typedef remove_if< numbers, not_equal_to<_,int_c<5> > >::type fives;
+BOOST_STATIC_ASSERT(equal_to< count_if< fives, equal_to<_,int_c<5> > >::type, size<fives>::type >::type::value));
+
+

+

Notes

+

+[1] The not_equal_to metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, equal_to, less, less_equal, greater, greater_equal +


+Table of Content | Reference
Last edited July 17, 2002 4:14 am \ No newline at end of file diff --git a/doc/ref/Reference/plus.html b/doc/ref/Reference/plus.html new file mode 100644 index 0000000..c39e75e --- /dev/null +++ b/doc/ref/Reference/plus.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/plus + + +

[Home]plus

Synopsis

+

+

+template<
+      typename T1
+    , typaname T2
+    , typaname T3 = integral_c<int,0>
+    , ...
+    , typaname Tn = integral_c<int,0>
+    >
+struct plus
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the sum of its arguments [1]. +

+

Definition

+

+

+#include "boost/mpl/arithmetic/plus.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
T1, T2, .., TnA model of Integral Constant
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef plus<t1,t2,..,tn>::type sum;A model of Integral ConstantEquivalent to typedef integral_c<typeof(t1::value + t2::value .. + tn::value), t1::value + t2::value .. + tn::value > sum;
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+

+typedef plus< integral_c<short,-1>, integral_c<long,10> >::type sum;
+BOOST_STATIC_ASSERT(sum::value == 9));
+BOOST_MPL_ASSERT_IS_SAME(sum::value_type, long);
+
+

+

Notes

+

+[1] The plus metafunction can be (and is expected to be) specialized by user to work on user-defined types that do not satisfy the Integral Constant requirements. The requirements listed here are the ones imposed by the default implementation.
+

+

See also

+

+Metafunctions, minus, multiplies, divides, modulus, negate +


+Table of Content | Reference
Last edited July 17, 2002 4:05 am \ No newline at end of file diff --git a/doc/ref/Reference/pop_back.html b/doc/ref/Reference/pop_back.html new file mode 100644 index 0000000..bea1777 --- /dev/null +++ b/doc/ref/Reference/pop_back.html @@ -0,0 +1,71 @@ + +boost::mpl::Reference/pop back + + +

[Home]pop_back

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct pop_back
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+pop_back performs a removal at the end of the sequence. The algorithm returns a new sequence which contains all the elements in the range [begin<Sequence>::type, prior< end<Sequence>::type >::type). The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/pop_back.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the erase operation
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef pop_back<Sequence>::type s;A model of Extensible Sequenceempty<Sequence>::type::value == falseEquivalent to typedef erase< Sequence, prior< end<Sequence>::type >::type >::type s;size<s>::type::value == size<Sequence>::type::value - 1
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef list<long>::type types1;
+typedef list<long,int>::type types2;
+typedef list<long,int,char>::type types3;
+

+typedef pop_back<types1>::type result1; +typedef pop_back<types2>::type result2; +typedef pop_back<types3>::type result3; +

+BOOST_STATIC_ASSERT(size<result1>::type::value == 0); +BOOST_STATIC_ASSERT(size<result2>::type::value == 1); +BOOST_STATIC_ASSERT(size<result3>::type::value == 2); +

+BOOST_MPL_ASSERT_IS_SAME(back<result2>::type, long); +BOOST_MPL_ASSERT_IS_SAME(back<result3>::type, int); +

+

+

Notes

+

+[1] The algorithm is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Extensible Sequence, erase, push_back, back, pop_front +


+Table of Content | Reference
Last edited July 17, 2002 3:56 am \ No newline at end of file diff --git a/doc/ref/Reference/pop_front.html b/doc/ref/Reference/pop_front.html new file mode 100644 index 0000000..90060d8 --- /dev/null +++ b/doc/ref/Reference/pop_front.html @@ -0,0 +1,71 @@ + +boost::mpl::Reference/pop front + + +

[Home]pop_front

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct pop_front
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+pop_front performs a removal at the beginning of the sequence. The algorithm returns a new sequence which contains all the elements in the range [next< begin<Sequence>::type >::type, end<Sequence>::type). The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/pop_front.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the erase operation
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef pop_front<Sequence>::type s;A model of Extensible Sequenceempty<Sequence>::type::value == falseEquivalent to typedef erase< Sequence, begin<Sequence>::type >::type s;size<s>::type::value == size<Sequence>::type::value - 1
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef list<long>::type types1;
+typedef list<int,long>::type types2;
+typedef list<char,int,long>::type types3;
+

+typedef pop_front<types1>::type result1; +typedef pop_front<types2>::type result2; +typedef pop_front<types3>::type result3; +

+BOOST_STATIC_ASSERT(size<result1>::type::value == 0); +BOOST_STATIC_ASSERT(size<result2>::type::value == 1); +BOOST_STATIC_ASSERT(size<result3>::type::value == 2); +

+BOOST_MPL_ASSERT_IS_SAME(front<result2>::type, long); +BOOST_MPL_ASSERT_IS_SAME(front<result3>::type, int); +

+

+

Notes

+

+[1] The algorithm is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Extensible Sequence, erase, push_front, front, pop_back +


+Table of Content | Reference
Last edited July 17, 2002 3:54 am \ No newline at end of file diff --git a/doc/ref/Reference/prior.html b/doc/ref/Reference/prior.html new file mode 100644 index 0000000..4a5d037 --- /dev/null +++ b/doc/ref/Reference/prior.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/prior + + +

[Home]prior

Synopsis +

+

+

+template<
+      typename T
+    >
+struct prior
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/prior.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, next +


+Table of Content | Reference
Last edited February 19, 2002 4:25 am \ No newline at end of file diff --git a/doc/ref/Reference/push_back.html b/doc/ref/Reference/push_back.html new file mode 100644 index 0000000..a5998f8 --- /dev/null +++ b/doc/ref/Reference/push_back.html @@ -0,0 +1,63 @@ + +boost::mpl::Reference/push back + + +

[Home]push_back

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct push_back
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+push_back performs an insertion at the end of the sequence. The algorithm returns a new sequence which contains type T as its last element. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/push_back.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the insert operation.
TA typeThe element to be inserted.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef push_back<Sequence,T>::type s;A model of Extensible SequenceEquivalent to typedef insert< Sequence,end<Sequence>::type,T >::type s;size<s>::type::value == size<Sequence>::type::value + 1; back<s>::type is identical to T
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef vector_c<bool,false,false,false,true,true,true,false,false> bools;
+typedef push_back<bools,false_c>::type message;
+BOOST_STATIC_ASSERT(back<message>::type::value == false);
+BOOST_STATIC_ASSERT((count_if<message, equal_to<_,false_c> >::type::value == 6));
+
+

+

Notes

+

+[1] The algorithm is can be viewed as a notational shorcut to more verbose insert< Sequence,end<Sequence>::type,T >::type, and is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Extensible Sequence, insert, back, pop_back, push_front +


+Table of Content | Reference
Last edited July 17, 2002 3:57 am \ No newline at end of file diff --git a/doc/ref/Reference/push_front.html b/doc/ref/Reference/push_front.html new file mode 100644 index 0000000..d0f3765 --- /dev/null +++ b/doc/ref/Reference/push_front.html @@ -0,0 +1,64 @@ + +boost::mpl::Reference/push front + + +

[Home]push_front

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct push_front
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+push_front performs an insertion at the beginning of the sequence. The algorithm returns a new sequence which contains type T as its first element. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/push_front.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceA sequence to handle the insert operation.
TA typeThe element to be inserted.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef push_front<Sequence,T>::type s;A model of Extensible SequenceEquivalent to typedef insert< Sequence,begin<Sequence>::type,T >::type s;size<s>::type::value == size<Sequence>::type::value + 1; front<s>::type is identical to T
+

+

Complexity

+

+Amortized constant time [1]. +

+

Example

+

+

+typedef list_c<int,1,2,3,5,8,13,21> something;
+BOOST_STATIC_ASSERT(size<something>::type::value == 7);
+typedef push_front< something,integral_c<int,1> >::type fibonacci;
+BOOST_STATIC_ASSERT(size<fibonacci>::type::value == 8);
+BOOST_STATIC_ASSERT((equal< fibonacci,list_c<int,1,1,2,3,5,8,13,21>,equal_to<_,_> >::type::value));
+
+

+

Notes

+

+[1] The algorithm is can be viewed as a notational shorcut to more verbose insert< Sequence,begin<Sequence>::type,T >::type, and is provided only if the sequence can meet the stated complexity requirements.
+

+

See also

+

+Extensible Sequence, insert, front, pop_front, push_back +


+Table of Content | Reference
Last edited July 17, 2002 3:53 am \ No newline at end of file diff --git a/doc/ref/Reference/range_c.html b/doc/ref/Reference/range_c.html new file mode 100644 index 0000000..95fdf02 --- /dev/null +++ b/doc/ref/Reference/range_c.html @@ -0,0 +1,71 @@ + +boost::mpl::Reference/range c + + +

[Home]range_c

Synopsis

+

+

+template<
+      typename T
+    , T Start
+    , T Finish
+    >
+struct range_c
+{
+    typedef integral_c<T,Start> start;
+    typedef integral_c<T,Finish> finish;
+};
+
+

+

Description

+

+range_c is a sorted Random Access Sequence of Integral Constants. It is not an Extensible Sequence, meaning that transformation algorithms, such as push_front or replace, are not applicable to it, at least directly - you need to copy the content of the range into a more suitable sequence, when needed [1]. +

+

Definition

+

+

+#include "boost/mpl/range_c.hpp"
+
+

+

Example

+

+

+typedef range_c<int,0,0> range0;
+typedef range_c<int,0,1> range1;
+typedef range_c<int,0,10> range10;
+

+BOOST_STATIC_ASSERT(size<range0>::type::value == 0); +BOOST_STATIC_ASSERT(size<range1>::type::value == 1); +BOOST_STATIC_ASSERT(size<range10>::type::value == 10); +

+BOOST_STATIC_ASSERT(empty<range0>::type::value); +BOOST_STATIC_ASSERT(!empty<range1>::type::value); +BOOST_STATIC_ASSERT(!empty<range10>::type::value); +

+BOOST_MPL_ASSERT_IS_SAME(begin<range0>::type, end<range0>::type); +BOOST_MPL_ASSERT_NOT_SAME(begin<range1>::type, end<range1>::type); +BOOST_MPL_ASSERT_NOT_SAME(begin<range10>::type, end<range10>::type); +

+BOOST_STATIC_ASSERT(front<range1>::type::value == 0); +BOOST_STATIC_ASSERT(back<range1>::type::value == 0); +BOOST_STATIC_ASSERT(front<range10>::type::value == 0); +BOOST_STATIC_ASSERT(back<range10>::type::value == 9); +

+

+

Notes

+

+[1] In fact, the most common application of range_c class is to simplify the creation of sorted list or vector: +

+

+typedef copy<
+      range_c<int,0,50>
+    , push_back<_,_>
+    , vector<>
+    >::type numbers;
+

+

+

See also

+

+Random Access Sequence, vector, vector_c, list, list_c +


+Table of Content | Reference
Last edited July 17, 2002 8:31 am \ No newline at end of file diff --git a/doc/ref/Reference/remove.html b/doc/ref/Reference/remove.html new file mode 100644 index 0000000..034f729 --- /dev/null +++ b/doc/ref/Reference/remove.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/remove + + +

[Home]remove

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    >
+struct remove
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a new sequence which contains all the elements from [begin<Sequence>::type, end<Sequence>::type) range except those that are identical to T. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/remove.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceThe original sequence.
TA typeA type to be removed.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef remove<Sequence,T>::type s;A model of Extensible SequenceEquivalent to typedef remove_if< Sequence,is_same<_,T> >::type t;.
+

+

Complexity

+

+Linear. Performs exactly size<Sequence>::type::value comparisons for equality. +

+

Example

+

+

+typedef list<int,float,char,float,float,double>::type types;
+typedef remove< types,float >::type result;
+typedef list<int,char,double>::type answer;
+BOOST_STATIC_ASSERT((equal< result,answer >::type::value));
+
+

+

See also

+

+Algorithms, remove_if, replace, replace_if, transform +


+Table of Content | Reference
Last edited July 17, 2002 8:43 am \ No newline at end of file diff --git a/doc/ref/Reference/remove_if.html b/doc/ref/Reference/remove_if.html new file mode 100644 index 0000000..9d30c15 --- /dev/null +++ b/doc/ref/Reference/remove_if.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/remove if + + +

[Home]remove_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pred
+    >
+struct remove_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns a new sequence which contains all the elements from [begin<Sequence>::type, end<Sequence>::type) range except those that satisfy the predicate Pred. The result sequence preserves all the functional and performance characteristics of the original Sequence, except its size and identity. +

+

Definition

+

+

+#include "boost/mpl/remove_if.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceThe original sequence.
PredAn unary Predicate [Lambda Expression]A removal condition.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef remove_if<Sequence,Pred>::type s;A model of Extensible Sequence
+

+

Complexity

+

+Linear. Performs exactly size<Sequence>::type::value applications of Pred. +

+

Example

+

+

+typedef list_c<int,1,4,5,2,7,5,3,5>::type numbers;
+typedef remove_if< numbers, greater<_,4> >::type result;
+typedef list_c<int,1,4,2,3>::type answer;
+BOOST_STATIC_ASSERT((equal< answer,result,equal_to<_,_> >::type::value));
+
+

+

See also

+

+Algorithms, remove, replace, transform +


+Table of Content | Reference
Last edited July 17, 2002 8:43 am \ No newline at end of file diff --git a/doc/ref/Reference/replace.html b/doc/ref/Reference/replace.html new file mode 100644 index 0000000..5955b72 --- /dev/null +++ b/doc/ref/Reference/replace.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/replace + + +

[Home]replace

Synopsis

+

+

+template<
+      typename Sequence
+    , typename OldType
+    , typename NewType
+    >
+struct replace
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Performs a replacement operation on the sequence. The algorithm returns a new sequence which contains all the elements from [begin<Sequence>::type, end<Sequence>::type) range where every type identical to OldType has been replaced with a NewType. The result sequence preserves all the functional and performance characteristics of the original Sequence, including its size, but not identity. +

+

Definition

+

+

+#include "boost/mpl/replace.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceThe original sequence.
OldTypeA typeA type to be replaced.
NewTypeA typeA type to replace with.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef replace<Sequence,OldType,NewType>::type s;A model of Extensible SequenceEquivalent to typedef replace_if< Sequence,NewType,is_same<_,OldType> >::type t;.
+

+

Complexity

+

+Linear. Performs exactly size<Sequence>::type::value comparisons for equality, and at most size<Sequence>::type::value insertions. +

+

Example

+

+

+typedef list<int,float,char,float,float,double>::type types;
+typedef replace< types,float,double >::type result;
+typedef list<int,double,char,double,double,double>::type answer;
+BOOST_STATIC_ASSERT((equal< result,answer >::type::value));
+
+

+

See also

+

+Algorithms, replace_if, transform +


+Table of Content | Reference
Last edited July 17, 2002 5:38 am \ No newline at end of file diff --git a/doc/ref/Reference/replace_if.html b/doc/ref/Reference/replace_if.html new file mode 100644 index 0000000..96a44ef --- /dev/null +++ b/doc/ref/Reference/replace_if.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/replace if + + +

[Home]replace_if

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Pred
+    , typename NewType
+    >
+struct replace_if
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Performs a conditional replacement operation on the sequence. The algorithm returns a new sequence which contains all the elements from [begin<Sequence>::type, end<Sequence>::type) range where every type that satisfies the predicate Pred has been replaced with a NewType. The result sequence preserves all the functional and performance characteristics of the original Sequence, including its size, but not identity. +

+

Definition

+

+

+#include "boost/mpl/replace_if.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceThe original sequence.
PredAn unary Predicate [Lambda Expression]The replacement condition.
NewTypeA typeA type to replace with.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef replace_if<Sequence,Pred,NewType>::type s;A model of Extensible SequenceEquivalent to typedef lambda<Pred>::type pred; typedef transform< Sequence, if_< apply1<pred,_1>,NewType,_1> >::type t;.
+

+

Complexity

+

+Linear. Performs exactly size<Sequence>::type::value applications of Pred, and at most size<Sequence>::type::value insertions. +

+

Example

+

+

+typedef list_c<int,1,4,5,2,7,5,3,5>::type numbers;
+typedef replace_if< numbers, greater<_,4>, int_c<0> >::type result;
+typedef list_c<int,1,4,0,2,0,0,3,0>::type answer;
+BOOST_STATIC_ASSERT((equal< answer,result,equal_to<_,_> >::type::value));
+
+

+

See also

+

+Algorithms, replace, transform +


+Table of Content | Reference
Last edited July 17, 2002 5:38 am \ No newline at end of file diff --git a/doc/ref/Reference/reverse.html b/doc/ref/Reference/reverse.html new file mode 100644 index 0000000..8e2f5ce --- /dev/null +++ b/doc/ref/Reference/reverse.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/reverse + + +

[Home]reverse

Synopsis +

+

+

+template<
+      typename Sequence
+    >
+struct reverse
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/reverse.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, fold, fold_reverse +


+Table of Content | Reference
Last edited February 19, 2002 4:11 am \ No newline at end of file diff --git a/doc/ref/Reference/size.html b/doc/ref/Reference/size.html new file mode 100644 index 0000000..17b5ad5 --- /dev/null +++ b/doc/ref/Reference/size.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/size + + +

[Home]size

Synopsis

+

+

+template<
+      typename Sequence
+    >
+struct size
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+size returns the number of elements in the sequence, that is, the number of elements in the range [begin<Sequence>::type,end<Sequence>::type). +

+

Definition

+

+

+#include "boost/mpl/size.hpp"
+
+

+

Parameters

+ + + +
 Parameter  Requirement  Description  
SequenceA model of Sequence
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef size<Sequence>::type s;A model of Integral ConstantEquivalent to typedef distance< begin<Sequence>::type,end<Sequence>::type >::type s;s::value >= 0
+

+

Complexity

+

+The complexity of the size algorithm directly depends on the implementation of the particular sequence it is applied to. In the worst case size has a linear complexity. As a general rule, if the Sequence is a Random Access Sequence, you can be certain that size<Sequence>::type is an amortized constant time operation. The opposite is not necessary true - for example, a model of Forward Sequence still can guarantee you an amortized constant time size complexity. Please refer the documentation page of the concrete sequence type for further information. +

+

Example

+

+

+typedef list0<> empty_list;
+typedef vector_c<int,0,1,2,3,4,5> numbers;
+typedef range_c<int,0,100> more_numbers;
+

+BOOST_STATIC_ASSERT(size<list>::type::value == 0); +BOOST_STATIC_ASSERT(size<numbers>::type::value == 5); +BOOST_STATIC_ASSERT(size<more_numbers>::type::value == 100); +

+

+

See also

+

+Sequence, empty, begin, end +


+Table of Content | Reference
Last edited July 17, 2002 3:51 am \ No newline at end of file diff --git a/doc/ref/Reference/sort.html b/doc/ref/Reference/sort.html new file mode 100644 index 0000000..1905d48 --- /dev/null +++ b/doc/ref/Reference/sort.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/sort + + +

[Home]sort

Synopsis +

+

+

+template<
+      typename Sequence
+    , typename Compare = less<_1,_2>
+    >
+struct sort
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/sort.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, lower_bound, upper_bound +


+Table of Content | Reference
Last edited February 19, 2002 4:22 am \ No newline at end of file diff --git a/doc/ref/Reference/transform.html b/doc/ref/Reference/transform.html new file mode 100644 index 0000000..5b8c84e --- /dev/null +++ b/doc/ref/Reference/transform.html @@ -0,0 +1,59 @@ + +boost::mpl::Reference/transform + + +

[Home]transform

Synopsis

+

+

+template<
+      typename Sequence
+    , typename Op
+    >
+struct transform
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Performs a transformation on the sequence. The algorithm returns a new sequence produced by applying the unary metafunction Op to every element in the [begin<Sequence>::type, end<Sequence>::type) range. The result sequence preserves all the functional and performance characteristics of the original Sequence, including its size, but not identity. +

+

Definition

+

+

+#include "boost/mpl/transform.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of Extensible SequenceThe original sequence.
OpAn unary [Lambda Expression]A transformation.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef transform<Sequence,Op>::type s;A model of Extensible Sequencesize<s>::type::value == size<Sequence>::type::value.
+

+

Complexity

+

+Linear. The operation Op is applied exactly size<Sequence>::type::value times. +

+

Example

+

+

+typedef list<char,short,int,long,float,double> types;
+typedef list<char*,short*,int*,long*,float*,double*> pointers;
+typedef transform< types,boost::add_pointer<_1> >::type result;
+BOOST_STATIC_ASSERT((equal<result,pointers>::value));
+
+

+

See also

+

+Algorithms, replace, replace_if, transform +


+Table of Content | Reference
Last edited July 17, 2002 5:47 am \ No newline at end of file diff --git a/doc/ref/Reference/transform_view.html b/doc/ref/Reference/transform_view.html new file mode 100644 index 0000000..e27ac54 --- /dev/null +++ b/doc/ref/Reference/transform_view.html @@ -0,0 +1,61 @@ + +boost::mpl::Reference/transform view + + +

[Home]transform_view

Synopsis

+

+

+template<
+      typename Sequence
+    , typename F
+    >
+struct transform_view
+{
+};
+
+

+

Description

+

+transform_view is a sequence wrapper that allows one to operate on the transformed sequence without actually creating one. +

+

Definition

+

+

+#include "boost/mpl/transform_view.hpp"
+
+

+

Parameters

+ + + + +
 Parameter  Requirement  Description  
SequenceA model of SequenceA sequence to wrap.
FA model of unary [Lambda Expression]A transformation metafunction.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef transform_view<Sequence,F> s;A model of Sequences is a sequence such that for each i in [begin<s>::type, end<s>::type) and for each j in [begin<Sequence>::type, end<Sequence>::type) i::type is identical to apply< lambda<F>::type, j::type >::type.size<Sequence>::type::value == size<s>::type::value.
+

+

Complexity

+

+Amortized constant time. +

+

Example

+

+Finds the largest type in a sequence. +

+

+typedef list<int,long,char,char[50],double> types;
+typedef max_element<
+      transform_view< types, size_of<_> >
+    >::type iter;
+BOOST_STATIC_ASSERT(iter::type::value == 50);
+
+

+

See also

+

+Sequences, filter_view, list, max_element +


+Table of Content | Reference
Last edited July 23, 2002 3:23 am \ No newline at end of file diff --git a/doc/ref/Reference/unique.html b/doc/ref/Reference/unique.html new file mode 100644 index 0000000..4302889 --- /dev/null +++ b/doc/ref/Reference/unique.html @@ -0,0 +1,62 @@ + +boost::mpl::Reference/unique + + +

[Home]unique

Synopsis +

+

+

+template<
+      typename Sequence
+    , typename Predicate = is_same<_1,_2>
+    >
+struct unique
+{
+    typedef implementation-defined type;
+};
+
+

+

Description +

+

+[to do] +

+

Definition +

+

+

+#include "boost/mpl/unique.hpp"
+
+

+

Parameters +

+ + + +
 Parameter  Requirement  Description  Default argument  
ParamA model of Concept[to do][to do]
+

+

Members +

+ + + +
 Member  Description  
type[to do]
+

+

Complexity +

+

+[to do] +

+

Example +

+

+

+[to do]
+
+

+

See also +

+

+Algorithms, erase, erase_if +


+Table of Content | Reference
Last edited February 19, 2002 4:15 am \ No newline at end of file diff --git a/doc/ref/Reference/upper_bound.html b/doc/ref/Reference/upper_bound.html new file mode 100644 index 0000000..4379743 --- /dev/null +++ b/doc/ref/Reference/upper_bound.html @@ -0,0 +1,60 @@ + +boost::mpl::Reference/upper bound + + +

[Home]upper_bound

Synopsis

+

+

+template<
+      typename Sequence
+    , typename T
+    , typename Pred
+    >
+struct upper_bound
+{
+    typedef unspecified type;
+};
+
+

+

Description

+

+Returns the last position in the sorted Sequence where T could be inserted without violating the ordering. +

+

Definition

+

+

+#include "boost/mpl/upper_bound.hpp"
+
+

+

Parameters

+ + + + + +
 Parameter  Requirement  Description  
SequenceA model of Forward SequenceA sorted sequence.
TA typeA type to search the position for.
PredA model of binary Predicate [Lambda Expression]A sort criteria.
+

+

Expression semantics

+

+ + + +
 Expression  Expression type  Precondition  Semantics  Postcondition 
typedef upper_bound< Sequence,T,Pred >::type i;A model of Forward Iteratori is the furthermost iterator in [begin<Sequence>::type, end<Sequence>::type) such that, for every iterator j in [begin<Sequence>::type, i), apply< lambda<Pred>::type, T, j::type >::type::value == false.
+

+

Complexity

+

+The number of comparisons is logarithmic: at most log(size<Sequence>::type::value) + 1. If Sequence is a Random Access Sequence then the number of steps through the range is also logarithmic; otherwise, the number of steps is proportional to size<Sequence>::type::value. +

+

Example

+

+

+typedef list_c<int,1,2,3,3,3,5,8> numbers;
+typedef upper_bound< numbers, int_c<3>, less<_,_> >::type iter;
+BOOST_STATIC_ASSERT((distance< begin<numbers>::type,iter >::type::value == 5));
+
+

+

See also

+

+Algorithms, sort, lower_bound +


+Table of Content | Reference
Last edited July 17, 2002 6:30 pm \ No newline at end of file diff --git a/doc/ref/Reference/vector.html b/doc/ref/Reference/vector.html new file mode 100644 index 0000000..968736d --- /dev/null +++ b/doc/ref/Reference/vector.html @@ -0,0 +1,77 @@ + +boost::mpl::Reference/vector + + +

[Home]vector

Synopsis

+

+

+template<
+      typename T1 = implementation-defined
+    , typename T2 = implementation-defined
+    , ...
+    , typename Tn = implementation-defined
+    >
+struct vector
+{
+};
+
+

+

Description

+

+An vector is a Random Access Sequence of types. It's also an Extensible Sequence that supports constant time insertion and removal of elements at the end (through push_back), and linear time insertion and removal of elements at the beginning or in the middle (through insert/erase algorithms). On compilers that support the typeof extension, vector is the simplest and in many cases the most efficient sequence [1]. +

+

Example

+

+

+typedef vector<float,double,long double> floats;
+typedef push_back<floating_types,my_float>::type ext_floats;
+typedef at_c<3,ext_floats>::type my;
+BOOST_STATIC_ASSERT((boost::is_same<my,my_float>::value));
+
+

+

Definition

+

+

+#include "boost/mpl/vector.hpp"
+#include "boost/mpl/vector/vector0.hpp"
+#include "boost/mpl/vector/vector10.hpp"
+...
+#include "boost/mpl/vector/vector50.hpp"
+
+

+

Notes

+

+[1] The typeof operator allows one to use overload resolution to implement a constant-time random access to elements of the sequence with minimum amount of code (in contrast to the usual brute-force approach the library has to resort to when the typeof operator is not available): +

+

+struct null_node
+{
+    static aux::type_wrapper<void_> item(...);
+};
+

+template< long N, typename T, typename Base > +struct node + : Base +{ + using Base::item; + static aux::type_wrapper<T> item(integral_c<long,N>); +}; +

+template< typename V, long N > +struct at +{ + typedef __typeof__(V::item(integral_c<long,N>())) wrapped_type_; + typedef typename wrapped_type_::type type; +}; +

+typedef node<1,char,node<0,int,null_node> > v; +typedef at<v,0>::type t; // constant-time random access! +BOOST_STATIC_ASSERT((is_same<t,int>::value)); +

+
+

+

See also

+

+Random Access Sequence, vector_c, list, list_c, range_c +


+Table of Content | Reference
Last edited July 22, 2002 4:28 pm \ No newline at end of file diff --git a/doc/ref/Reference/vector_c.html b/doc/ref/Reference/vector_c.html new file mode 100644 index 0000000..dbf2b29 --- /dev/null +++ b/doc/ref/Reference/vector_c.html @@ -0,0 +1,58 @@ + +boost::mpl::Reference/vector c + + +

[Home]vector_c

Synopsis

+

+

+template<
+      typename T
+    , T C1 = implementation-defined
+    , T C2 = implementation-defined
+    , ...
+    , T CN = implementation-defined
+    >
+struct vector_c
+{
+};
+
+

+

Description

+

+vector_c is a shorcut interface whose whole purpose is to make the creation of a vector of Integral Constants less verbose: +

+

+typedef vector_c<unsigned long,-1,0,1,1,-1,0,0,1,-1> data;
+
+

+If vector_c didn't exist, instead of the above line you would have to write this: +

+

+typedef vector<
+      integral_c<unsigned long,-1>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,-1>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,0>
+    , integral_c<unsigned long,1>
+    , integral_c<unsigned long,-1>
+    > data;
+
+

+

Definition

+

+

+#include "boost/mpl/vector_c.hpp"
+#include "boost/mpl/vector/vector0_c.hpp"
+#include "boost/mpl/vector/vector10_c.hpp"
+...
+#include "boost/mpl/vector/vector50_c.hpp"
+
+

+

See also

+

+Random Access Sequence, vector, list, list_c, range_c +


+Table of Content | Reference
Last edited July 17, 2002 8:01 am \ No newline at end of file diff --git a/doc/ref/Sequence.html b/doc/ref/Sequence.html new file mode 100644 index 0000000..f7692f4 --- /dev/null +++ b/doc/ref/Sequence.html @@ -0,0 +1,49 @@ + +boost::mpl::Sequence + + +

[Home]Sequence

Description

+

+A Sequence (or, more precisely, an Input Sequence) is a compile-time entity to which you can apply begin/end operations in order to get iterators for accessing the range of its elements. In general, a sequence does not guarantee that its content doesn't change from one iteration to another, or between different compilation sessions [1]. See Forward Sequence for the definition of the concept that imposes such additional requirements. +

+

Valid expressions

+

+ + + + +
 Expression  Expression type  
typename begin<s>::typeA model of Input Iterator
typename end<s>::typeA model of Input Iterator
+

+

Expression semantics

+

+See the description of begin/end operations. +

+

Invariants

+

+For any sequence s the following invariants always hold: +

    +
  • [begin<s>::type, end<s>::type) is always a valid range; +
  • an algorithm that iterates through the range [begin<s>::type, end<s>::type) will pass through every element of s (once); +
  • begin<s>::type is identical to end<s>::type if and only if the sequence s is empty. +
+

+

Models

+

+

+

+

Notes

+

+[1] For example, a sequence might implement an interface to a compile-time random-number generator; for such sequence the begin/end invocation might return different iterators on every subsequent compilation of the code.
+

+

See also

+

+Sequences, Forward Sequence, Input Iterator, begin, end +


+Table of Content
Last edited July 21, 2002 5:55 pm \ No newline at end of file diff --git a/doc/ref/Sequences.html b/doc/ref/Sequences.html new file mode 100644 index 0000000..6c1c77e --- /dev/null +++ b/doc/ref/Sequences.html @@ -0,0 +1,46 @@ + +boost::mpl::Sequences + + +

[Home]Sequences

    +
  1. Concepts +
      +
    1. Sequence +
    2. Forward Sequence +
    3. Bidirectional Sequence +
    4. Random Access Sequence +
    5. Extensible Sequence +
    +
  2. Classes +
      +
    1. vector +
    2. list +
    3. vector_c +
    4. list_c +
    5. range_c +
    +
  3. Views +
      +
    1. transform_view +
    2. filter_view +
    +
  4. Algorithms +
      +
    1. begin/end +
    2. size +
    3. empty +
    4. front +
    5. back +
    6. at/at_c +
    7. push_front +
    8. push_back +
    9. pop_front +
    10. pop_back +
    11. clear +
    12. insert +
    13. insert_range +
    14. erase +
    +
+


+Table of Content
Last edited July 19, 2002 2:14 am \ No newline at end of file diff --git a/doc/ref/Table_of_Content.html b/doc/ref/Table_of_Content.html new file mode 100644 index 0000000..107548c --- /dev/null +++ b/doc/ref/Table_of_Content.html @@ -0,0 +1,14 @@ + +boost::mpl::Table of Content + + +

[Home]Table of Content

    +
  1. Sequences +
  2. Iterators +
  3. Algorithms +
  4. Metafunctions +
  5. Categorized index +
  6. Acknowledgements +
+


+Table of Content
Last edited July 17, 2002 10:15 am \ No newline at end of file diff --git a/doc/ref/Trivial_Iterator.html b/doc/ref/Trivial_Iterator.html new file mode 100644 index 0000000..eb40e71 --- /dev/null +++ b/doc/ref/Trivial_Iterator.html @@ -0,0 +1,46 @@ + +boost::mpl::Trivial Iterator + + +

[Home]Trivial Iterator

Description

+

+A Trivial Iterator i is a type that represents a reference to an element of some Sequence, and allows to access the element through its nested type member [1]. A trivial iterator does not define any traversal operations. +

+

Definitions

+

+

    +
  • a trivial iterator can be dereferenceable, meaning that accessing its nested type member is a well-defined operation. +
+

+

Valid expressions

+

+ + + +
 Expression  Expression type  
typename i::typeA type
+

+

Expression semantics

+

+ + + +
 Expression  Complexity  Precondition  Semantics  Postcondition  
typename i::typeAmortized constant timei is dereferenceablei::type is identical to the type of the pointed element
+

+

Invariants

+

+For any trivial iterators i and j the following invariants always hold: +

+

    +
  • i and j are identical if and only if they are pointing to the same element; +
  • if i is dereferenceable, and j is identical to i, then j is dereferenceable as well; +
  • if i and j are identical and dereferenceable, then i::type and j::type are identical. +
+

+

Notes

+[1] Any trivial iterator is a model of [Nullary Metafunction Class] concept.
+

+

See also

+

+Sequence, Input Iterator +


+Table of Content
Last edited July 15, 2002 10:46 am \ No newline at end of file diff --git a/doc/ref/mpl_logo.jpg b/doc/ref/mpl_logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a1481baf72b2f4e1543e32039ea839e1523336d GIT binary patch literal 1428 zcmex=Cs!8|6AP2f<1ga{;jKq0}%z`*1H!I1D_5rL}(hYSl3 zh|kso_8|j90RsbrAOizq00V9lAn~ykkSCs`~NmW3j+@a z2L~qy4<{#&AU7AcpeR2N55K5{u&}7Gu!JBF7(gj78-rlv<>uz);}ziJ6AI}LmrEaic2l3Sq;<>GBUhe$S-SP;)u&&>(#qPVE!%eN+Ou!w?&0a>?bDZU zKYsoBcR>awCPpR}7OB@po<@jRgxYSHBE93 z7ELZT`KZbUasa!U>7h$5lS3AZr?`fim83p`I{~)~)Dceje~W>K8EmH@gFVC7(8jOD zucv#xzVW77XI;dg zZ5xv_+pLSvPRsj}naV4-`_1m;zhXxFFa65DvGe!7MPKz6wio}J=BM#WK5a3#;FO^E zo3{02&z^B>llIo%@AHCRt-kt8uKkC7ptt_3{P2^hH^1L)pLq4tCyf&)GQ}_U-QRre zO-ttLrmIdEMy^xPEG_ET1 ze=C+YM{jOWt8wM6)LH~{(X49@@n literal 0 HcmV?d00001 diff --git a/doc/ref/mpl_wiki.css b/doc/ref/mpl_wiki.css new file mode 100644 index 0000000..a6f6041 --- /dev/null +++ b/doc/ref/mpl_wiki.css @@ -0,0 +1,41 @@ +body +{ + background-color: white; + color: black; +} + +sup +{ + font-size: x-small; + font-weight: lighter; +} + +a:link, +a:visited +{ + color: #505050; +} + + pre a:link +,pre a:visited +,code a:link +,code a:visited +{ + color: #505050; + text-decoration: none; +} + + a.back-link:link +,a.back-link:visited +{ + color: black; + text-decoration: none; +} + +pre +{ + border-style: none none none solid; + border-width: 1px; + border-color: silver; + padding-left: 1em; +} diff --git a/doc/src/acknw.sgml b/doc/src/acknw.sgml new file mode 100644 index 0000000..df621e4 --- /dev/null +++ b/doc/src/acknw.sgml @@ -0,0 +1,18 @@ + +
+Acknowledgements</> + +<para> +Following is a list of people who in one or another way contributed to the library development. The list is work in progress! +</> + +<para> +David Abrahams, Emily Winch, Eric Friedman, Vesa Karvonen, Peter Dimov, Mat Marcus, Fernando Cacciola, Paul Mensonides, David B. Held, John Bandela, Arnaldur Gylfason, Hamish Mackenzie. +</> + +<formalpara> +<title>Copyright on this document</> +<para>Copyright © 2002 Aleksey Gurtovoy, David Abrahams and Emily Winch.</> +</> + +</section> diff --git a/doc/src/apply_if.sgml b/doc/src/apply_if.sgml new file mode 100644 index 0000000..0f8bf91 --- /dev/null +++ b/doc/src/apply_if.sgml @@ -0,0 +1,130 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="applyif"> +<title>apply_if</> + +<para> +In run-time &Cxx;, it is guaranteed that when we reach an <literal>if</> statement, only one branch will be executed. Executing the branch for which the result is not required would be unnecessary and inefficient. More importantly, frequently the non-required branch is invalid, and executing it would cause an error. For instance, the following code would be badly broken if both branches of the statement were evaluated: +</> + +<programlisting> +<![CDATA[ +void fun(giraffe* g) +{ + if (g) + cout << g->name(); + else + cout << "no giraffe"; +} +]]> +</> + +<para> +In compile-time world, things are different. Which parameters to <literal>if_</> template are instantiated is determined by the form of each template parameter and the corresponding language rules (<citation><xref linkend="ref.ISO98"></>, section 14.7.1), not by the value of the compile-time expression being switched on. That means that if, in attempt to process a particular <literal>if_</> construct, the compiler determines that one of its <quote>branch</> template parameters is ill-formed, it will issue a diagnostics even if the value of compile-time expression would lead to <quote>choosing</> the other, valid parameter type. +</> + +<para> +To clarify what we just said, here is a broken first attempt at writing a <literal>pointed_type</> metafunction, that when instantiated for a <literal>T</> that is either a plain pointer or a smart pointer, <quote>returns</> the pointed type: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct pointed_type +{ + typedef typename mpl::if_< + boost::is_pointer<T> + , typename boost::remove_pointer<T>::type + , typename T::element_type // #1 + >::type type; +}; + +typedef pointed_type< std::auto_ptr<int> >::type int_ptr; // ok +typedef pointed_type<char*>::type char_ptr; // error in line #1! +]]> +</> + +<para> +If we try to compile the above, we will get something like this: +</> + +<programlisting> +Error: name followed by "::" must be a class or namespace name +</> + +<para> +because the expression <literal>typename T::element_type</> is not valid in case of <literal>T == char*</>. +</> + +<para> +Here's what we need to do to make <literal>pointed_type</> work for plain pointers: + +<footnote><para> +It would be easy to implement <literal>pointed_type</> using partial specialization to distinguish the case where <literal>T</> is a pointer. <literal>if_</> is used here to avoid creating a complicated example. +</></> + +instead of instantiating our two potential results before passing them to <literal>if_</>, we need to write metafunctions that can be used to instantiate the results; then we can use <literal>if_</> to choose a metafunction, and only then should we use that function to get the result. +</> + +<para> +<literal>boost::remove_pointer</> already is a metafunction. We just need to write an auxiliary function to return the <literal>element_type</> of a pointer type: +</> + +<programlisting> +<![CDATA[ +namespace aux { +template< typename T > +struct element_type +{ + typedef typename T::element_type type; +}; +} +]]> +</> + +<para> +Now we can select the metafunction to call based on the result of <literal>boost::is_pointer</>, and then <emphasis>apply</> it to form the result: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct pointed_type +{ + private: + // pick a metafunction + typedef typename mpl::if_< + boost::is_pointer<T> + , boost::remove_pointer<T> + , aux::element_type<T> + >::type func_; // #1 + + public: + // apply the metafunction + typedef typename func_::type type; +}; +]]> +</> + +<para> +The key knowledge that makes the above viable is that in line #1 the compiler is <emphasis>guaranteed</> not to instantiate <literal>boost::remove_pointer<T></> and <literal>aux::element_type<T></> templates, - even although they are passed as actual arguments to the <literal>if_</>. +</> + +<para> +The described technique is so common in template metaprograms, that it makes sense to facilitate the selection of the nested <literal>type</> member by introducing a high level equivalent to <literal>if_</> that will do <literal>func_::type</> operation as a part of its invocation. The MPL provides such a template - it's called <literal>apply_if</>. Using it, we can re-write the above code as simply as: +</> + +<programlisting> +[<![CDATA[ +template< typename T > +struct pointed_type +{ + typedef typename mpl::apply_if< + boost::is_pointer<T> + , boost::remove_pointer<T> + , aux::element_type<T> + >::type type; +}; +]]> +</> + +</section> diff --git a/doc/src/apply_if2.sgml b/doc/src/apply_if2.sgml new file mode 100644 index 0000000..0ee49a2 --- /dev/null +++ b/doc/src/apply_if2.sgml @@ -0,0 +1,55 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="applyif2"> +<title>apply_if, part 2</> + +<para> +Besides solving the <quote>making the code compile</> problem, the <literal>apply_if</> technique we've just learned can be also used to improve metaprogram efficiency. +</> + +<para> +Suppose we want to define a high-level wrapper around <literal>boost::remove_pointer</> traits template, which will strip the pointer qualification conditionally. We will call it <literal>remove_pointer_if</>: +</> + +<programlisting> +<![CDATA[ +template< + typename Condition + , typename T + > +struct remove_pointer_if +{ + typedef typename mpl::if_< + Condition + , typename boost::remove_pointer<T>::type + , T + >::type type; +}; +]]> +</> + +<para> +The above works the first time, but it's not the most optimal implementation. Similar to our previous examples, <literal>boost::remove_pointer<T></> gets instantiated even if its result is never used. In the metaprogramming world compilation time is an important resource <citation><xref linkend="ref.Abr01"></>, and it is wasted by unnecessary template instantiations. +</> + +<para> +Let's see what we need to substitute <literal>if_</> by <literal>apply_if</> here. We already have one metafunction to pass to <literal>apply_if</> - <literal>boost::remove_pointer<T></>, but we need a second one, - let's call it <literal>f</>, - such as <literal>f<T>::type == T</>. We could write this one ourselves, but fortunately &MPL; already provides us with a template that matches this exact definition - it's called <literal>identity</>. Applying this knowledge, we get: +</> + +<programlisting> +<![CDATA[ +template< + typename Condition + , typename T + > +struct remove_pointer_if +{ + typedef typename mpl::apply_if< + Condition + , boost::remove_pointer<T> + , mpl::identity<T> + >::type type; +}; +]]> +</> + +</section> diff --git a/doc/src/articleinfo.sgml b/doc/src/articleinfo.sgml new file mode 100644 index 0000000..9ed58c4 --- /dev/null +++ b/doc/src/articleinfo.sgml @@ -0,0 +1,2 @@ +<articleinfo> +</articleinfo> diff --git a/doc/src/bibliography.sgml b/doc/src/bibliography.sgml new file mode 100644 index 0000000..3268196 --- /dev/null +++ b/doc/src/bibliography.sgml @@ -0,0 +1,69 @@ +<bibliography id="bibliography"> +<title>Bibliography</> + +<biblioentry id="ref.Abr01"> + <abbrev>Abr01</> + <authorgroup> + <author><firstname>David</><surname>Abrahams</></> + <author><firstname>Carlos Pinto</><surname>Coelho</></> + </> + <title><ulink url="http://users.rcn.com/abrahams/instantiation_speed/index.html">Effects of Metaprogramming Style on Compilation Time</></> + <date>2001</> +</biblioentry> + +<biblioentry id="ref.Ale00"> + <abbrev>Ale00</> + <author><firstname>Andrei</><surname>Alexandrescu</></> + <title><ulink url="http://www.cuj.com/experts/1810/alexandr.htm">On Conversions between Types and Values</></> + <publishername>C/C++ Users Journal</> + <date>October 2000</> +</biblioentry> + +<biblioentry id="ref.BBL"> + <abbrev>BBL</> + <title>Boost Bind library</> + <bibliomisc><ulink url="http://www.boost.org/libs/bind/bind.html"></></> +</biblioentry> + +<biblioentry id="ref.ISO98"> + <abbrev>ISO98</> + <title>ISO/IEC 14882:1998(E), Programming languages — C++</> + <orgname>ISO/IEC</> + <date>1998</> +</biblioentry> + +<biblioentry id="ref.PRE"> + <abbrev>PRE</> + <author><firstname>Vesa</><surname>Karvonen</></> + <title>Boost Preprocessor Metaprogramming library</> + <bibliomisc><ulink url="http://www.boost.org/libs/preprocessor/doc/"></></> +</biblioentry> + +<biblioentry id="ref.TTL"> + <abbrev>TTL</> + <title>Boost Type Traits library</> + <bibliomisc><ulink url="http://www.boost.org/libs/type_traits/"></></> +</biblioentry> + +<biblioentry id="ref.SAL"> + <abbrev>SAL</> + <title>Boost Static Assert library</> + <bibliomisc><ulink url="http://www.boost.org/libs/static_assert/static_assert.htm"></></> +</biblioentry> + +<biblioentry id="ref.Vel95a"> + <abbrev>Vel95a</> + <author><firstname>Todd</><surname>Veldhuizen</></> + <title><ulink url="http://osl.iu.edu/~tveldhui/papers/Template-Metaprograms/meta-art.html">Using C++ template metaprograms</></> + <biblioset relation='journal'> + <title>C++ Report</> + <publishername>SIGS Publications Inc.</> + <issn>1040-6042</> + </> + <volumenum>7</> + <issuenum>4</> + <pagenums>36-43</> + <date>May 1995</> +</biblioentry> + +</bibliography> diff --git a/doc/src/body.sgml b/doc/src/body.sgml new file mode 100644 index 0000000..672b57d --- /dev/null +++ b/doc/src/body.sgml @@ -0,0 +1,37 @@ +<!doctype article public "-//OASIS//DTD DocBook V4.1//EN" +[ +<!-- abbreviations --> +<!entity Boost "<literal>Boost</>"> +<!entity Cxx "C++"> +<!entity C "C"> +<!entity MPL "MPL"> +<!entity BMPL "Boost Metaprogramming Library"> +<!entity mdat "metadata"> +<!entity mping "metaprogramming"> +<!entity mfn "metafunction"> +<!entity unspec "/*unspecified*/"> + +<!-- physical entities --> +<!entity articleinfo SYSTEM "articleinfo.sgml"> +<!entity preface SYSTEM "preface.sgml"> +<!entity tutorial SYSTEM "tutorial.sgml"> +<!entity metafunctions SYSTEM "metafunctions.sgml"> +<!entity if SYSTEM "if.sgml"> +<!entity applyif SYSTEM "apply_if.sgml"> +<!entity applyif2 SYSTEM "apply_if2.sgml"> +<!entity technical SYSTEM "technical.sgml"> +<!entity acknw SYSTEM "acknw.sgml"> +<!entity bibliography SYSTEM "bibliography.sgml"> +]> + +<article> +<title>The Boost &MPL; Library</> + +&articleinfo; +&preface; +&tutorial; +&technical; +&acknw; +&bibliography; + +</article> diff --git a/doc/src/howtos.sgml b/doc/src/howtos.sgml new file mode 100644 index 0000000..b15df69 --- /dev/null +++ b/doc/src/howtos.sgml @@ -0,0 +1,58 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="howtos"> +<title>How-to's</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="howtos.search"> +<title>How to find something in a sequence?</> + +<para> +If you just want to make an enquiry if a sequence contains a type with certain properties, you can do it like that: +</> + +<programlisting> +<![CDATA[ +typedef mpl::list5<> types; +typedef mpl::contains<types,int>::type res; // res::value == true +]]> +</> + +<para> +A predicate version of <literal>contains</> algorithm is spelled <literal>any</>: +</> + +<programlisting> +<![CDATA[ +// find if any type in 'types' is derived from 'my' +typedef mpl::any<types, mpl::is_convertible<_1,my> >::type res; +]]> +</> + +<para> +Now, if you really want to find type in a sequence - that is, to obtain an iterator on its position, when the should-be-known-from-STL <literal>find</> and <literal>find_if</> algorithms are most probably exactly what you need: +</> + +<programlisting> +<![CDATA[ +// find if any type in 'types' is derived from 'my' +typedef mpl::find<types, int >::type iterator; +typedef mpl::find_if<types, mpl::is_convertible<_1,my> >::type iterator; +]]> +</> + +<para> +Unless, of course, the sequence is sorted. If it is, then the other known names come into the play - <literal>lower_bound</>, <literal>upper_bound</>, or <literal>binary_search</>: +</> + +<programlisting> +<![CDATA[ +// find if any type in 'types' is derived from 'my' +typedef mpl::lower_bound<types, mpl::int_c<5>, mpl::less<_1,_2> >::type iterator; +typedef mpl::upper_bound<types, mpl::int_c<5>, mpl::less<_1,_2> >::type iterator; +typedef mpl::binary_search<types, mpl::int_c<5>, mpl::less<_1,_2> >::type iterator; +]]> +</> + +</section> + +</section> diff --git a/doc/src/if.sgml b/doc/src/if.sgml new file mode 100644 index 0000000..8f68685 --- /dev/null +++ b/doc/src/if.sgml @@ -0,0 +1,66 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="if"> +<title>Compile-time if</> + +<para> +The most interesting template metaprograms often contain a lot of decision-making code. Some of conditional decisions/behavior can be handled directly by (partial) class template specialization or function overloading <citation><xref linkend="ref.Vel95a"></>, <citation><xref linkend="ref.Ale00"></>, but in general there is a need for a standalone library primitive that would allow one to choose between two types basing on a compile-time expression. In <literal>boost::mpl</> such primitive is called <literal>if_</>: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct heap_holder +{ + // ... + private: + boost::scoped_ptr<T> m_object; +}; + +template< typename T > +struct stack_holder +{ + // ... + private: + T m_object; +}; + +template< typename T > +struct can_be_on_stack + : mpl::bool_c< (sizeof(T) <= sizeof(double)) > +{ +}; + +// use 'if_' to choose where to store 'T' member +template< typename T > +struct lightweight + : private mpl::if_< + can_be_on_stack<T> + , stack_holder<T> + , heap_holder<T> + >::type +{ + // ... +}; +]]> +</> + +<para> +Note that the first template parameter of the <literal>if_</> template is a type that should be a model of Integral Constant concept. The library also provides a less generic but sometimes more convenient form that accepts a condition in form of non-type <literal>bool</> template parameter: +</> + +<programlisting> +<![CDATA[ +template< typename T > +struct lightweight + : private mpl::if_c< + (sizeof(T) <= sizeof(double)) + , stack_holder<T> + , heap_holder<T> + >::type +{ + // ... +}; +]]> +</> + +</section> diff --git a/doc/src/lambda.sgml b/doc/src/lambda.sgml new file mode 100644 index 0000000..45846cd --- /dev/null +++ b/doc/src/lambda.sgml @@ -0,0 +1,30 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="lambda"> +<title>Lambda facility</> + +<para> +<firstterm>Lambda expressions</> is a way of inline meta-function composition. + +building more complex, more interesting functions from the existing ones. The simplest case of function composition is an operation of taking the result from one function (<literal>g</>) and using that as the argument to another function (<literal>f</>) - <literal>f(g(x))</>. [Talk about run-time &Cxx; facilities to do function composition in &Cxx; - SGI STL <literal>compose1</>/<literal>compose2</>, Boost Compose library, Boost Bind library] +</> + +<para> +The library provide support for several styles of function composition. The facilities differ in portability, implementation complexity, readability, and performance characteristics. +</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="bind.compose"> +<title>compose</> + +<programlisting> +<![CDATA[ +using mpl::placeholders; +typedef mpl::bind< mpl::make_f2<boost::is_same>,int,_2 > is_int; +typedef mpl::bind< add_pointer,mpl::bind<add_const,_1> > add_const_pointer; +]]> +</> + + +</section> + +</section> diff --git a/doc/src/metafunctions.sgml b/doc/src/metafunctions.sgml new file mode 100644 index 0000000..afd7234 --- /dev/null +++ b/doc/src/metafunctions.sgml @@ -0,0 +1,37 @@ +<section id="metafunctions"> +<title>Metafunctions</> + +<para> +In &MPL;, the metaprogramming equivalent of a function is a <firstterm>class template</> containing a nested <literal>typedef</> member aptly named <quote>type</>: +</> + +<programlisting> +<![CDATA[ +// on the face of it, not very useful +template< typename T > +struct identity +{ + typedef T type; +}; + +// perhaps more useful +template< typename T > +struct result_type +{ + typedef typename T::result_type type; +}; +]]> +</> + +<para> +<quote>Invoking</> a metafunction is as simple as instantiating the class template with particular template parameters (metafunction <quote>arguments</>) and accessing the result through the nested <literal>type</> member: +</> + +<programlisting> +<![CDATA[ +typedef identity<int>::type t1; // t1 == int +typedef result_type< std::unary_function<int,bool> >::type t2; // t2 == bool +]]> +</> + +</section> diff --git a/doc/src/preface.sgml b/doc/src/preface.sgml new file mode 100644 index 0000000..85bb6bc --- /dev/null +++ b/doc/src/preface.sgml @@ -0,0 +1,49 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="preface"> +<title>Preface</> + +<para>The &MPL; library is a &Cxx; template metaprogramming framework of compile-time algorithms, sequences and metafunction classes. The two main documentation sources for the library is <quote>the MPL paper</>, and the library's reference documentation. If you haven't heard about the MPL before, we suggest you to start with the paper, and then move on to the reference documentation and the information in this document. +</> + +<itemizedlist mark="box"> + +<listitem><simpara> +A. Gurtovoy, D. Abrahams, <ulink url="./paper/html/index.html">The Boost C++ Metaprogramming Library</>, March 2002 | [<ulink url="./paper/mpl_paper.html">as single .html</>]</></listitem> + +<listitem> +<ulink url="./ref/Table_of_Content.html">Reference documentation</> + <orderedlist> + <listitem><simpara><ulink url="./ref/Sequences.html">Sequences</></></> + <listitem><simpara><ulink url="./ref/Iterators.html">Iterators</></></> + <listitem><simpara><ulink url="./ref/Algorithms.html">Algorithms</></></> + <listitem><simpara><ulink url="./ref/Metafunctions.html">Metafunctions</></></> + <listitem><simpara><ulink url="./ref/Categorized_index.html">Categorized index</></></> + </orderedlist> +</listitem> + +</itemizedlist> + +</section> + +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="source"> +<title>Sources</> + +<para> +The latest library sources are available from: +</> + +<itemizedlist mark="box"> + <listitem><simpara>The <ulink url="http://www.boost.org/more/download.html#CVS">boost CVS</>, <literal>mpl_v2</> branch (<literal>cvs update -P -rmpl_v2 boost/mpl boost/type_traits libs/mpl</>)</></> + <listitem><simpara>From here - <ulink url="http://www.mywikinet.com/mpl/mpl_23_jul_02.zip"></></></> + +</itemizedlist> + +<para> +The library also requires the latest version of Boost Preprocessor library, that can be also obtained from <ulink url="http://www.boost.org/more/download.html#CVS">boost CVS</> or from here - <ulink url="http://www.mywikinet.com/mpl/preprocessor_19_jul_02.zip"></>. +</> + +<para>A full archive that contains the library itself + all its dependencies - and therefore can be installed over a clean <ulink url="http://boost.sourceforge.net/release/boost_1_28_0.zip">Boost 1.28 distribution</> - is available from here - <ulink url="http://www.mywikinet.com/mpl/mpl_23_jul_02_full.zip"></>. +</> + +</section> diff --git a/doc/src/sequences.sgml b/doc/src/sequences.sgml new file mode 100644 index 0000000..2494f2d --- /dev/null +++ b/doc/src/sequences.sgml @@ -0,0 +1,30 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="sequences"> +<title>Working with type sequences</> + +<para> +If we were to design a generative container library, our first attempt could be something like this: +</> + +<programlisting> +<![CDATA[ +namespace ctl { // Container Template Library + +template< + typename T + , typename Features + > +class container +{ + // ... +}; + +} // namespace ctl +]]> +</> + +<para> +Here, <literal>container</> template is a single generative interface to all the , and we would like to pass to a possibly numerous features of a container as a single type. +</> + +</section> diff --git a/doc/src/technical.sgml b/doc/src/technical.sgml new file mode 100644 index 0000000..d59b73e --- /dev/null +++ b/doc/src/technical.sgml @@ -0,0 +1,52 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="technical"> +<title>Technical details</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="details.headers"> +<title>Physical structure</> + +<para> +The library provides you with a fine-grained header structure with one header per public component (class/function template), with the header named after the component; for example, <literal>boost::mpl::apply<></> template is defined in the header <literal>boost/mpl/apply.hpp</>. This scheme both ensures that you don't pay for what you don't use in terms of compilation time/header dependencies, and frees you from memorizing/looking up header/component correspondence. Several composite headers for the entities that are likely to be used together (e.g. logical operations - <literal>logical_or</>, <literal>logical_and</>, etc.) are also provided. It allows one to avoid the burden of spelling many <literal>#include</> directives in programs that make an intensive use of the library facilities. + +<footnote id="note.headers"><para>The Boost Preprocessor library <citation><xref linkend="ref.PRE"></> exposes a very similar physical organization; in fact, the libraries even share the common subdirectory naming (<literal>mpl/arithmetic</> <-> <literal>preprocessor/arithmetic</>, <literal>mpl/comparison</> <-> <literal>preprocessor/comparison</>, etc.).</></> + +</> + +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="details.depend"> +<title>Dependencies</> + +<para> +Besides <literal>boost/config.hpp</> header, the MPL heavily depends on two other Boost libraries - the Boost Preprocessor library <citation><xref linkend="ref.PRE"></>, and the Type Traits library <citation><xref linkend="ref.TTL"></>. These dependencies are essential and cannot be eliminated. In addition to those, the <literal>boost/mpl/assert_is_same.hpp</> header depends on Boost Static Assert library <citation><xref linkend="ref.SAL"></>. The library tests and examples may depend on some additional Boost libraries, e.g. Boost Bind <citation><xref linkend="ref.BBL"></>; you don't have to have those unless you are interested in actually compiling the tests/examples (probably you are, though). +</> + +</section> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="details.portability"> +<title>Portability</> + +<para> +Below is the list of compilers the library has been tested with: +</> + +<itemizedlist mark="box"> +<listitem><simpara>Microsoft Visual C++ 6.0, SP 5</></> +<listitem><simpara>Microsoft Visual C++ .NET (7.0)</></> +<listitem><simpara>Metrowerks CodeWariror 7.2/8.1</></> +<listitem><simpara>Intel C++ Compiler 5.0, 6.0</></> +<listitem><simpara>GCC 2.95.3-5</></> +<listitem><simpara>GCC 3.1</></> +<listitem><simpara>Comeau C/C++ 4.2.45/4.3.0</></> +<listitem><simpara>Borland C++ 5.5.1</></> +</> + +<para>An incomplete matrix of recent test compilation results is available from here - <ulink url="http://www.mywikinet.com/mpl/log.html"></>. +</> + +</section> + +</section> diff --git a/doc/src/tutorial.sgml b/doc/src/tutorial.sgml new file mode 100644 index 0000000..be77b98 --- /dev/null +++ b/doc/src/tutorial.sgml @@ -0,0 +1,29 @@ +<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section --> +<section id="tutorial"> +<title>Mini-tutorial</> + +<!-- ||||||||||||||||||||||||||||| subsection --> +<section id="tutorial.conventions"> +<title>Conventions used</> + +<para> +The examples used through this tutorial use fully qualified names, e.g. <literal>std::vector</> instead of plain <literal>vector</>. Any unqualified name refers to a local entity defined in the example itself. The names from <literal>boost::mpl</> namespace are referred to using <literal>mpl</> namespace alias (e.g. <literal>mpl::apply</> instead of <literal>boost::mpl::apply</>), as if the following namespace alias definition were in effect: +</> + +<programlisting> +<![CDATA[ +namespace mpl = boost::mpl; +]]> +</> + +<para>Note that the library offers a special header, <literal>boost/mpl/alias.hpp</>, including which gives you a rough equivalent of the above. Alternatively, you can always spell the namespace alias definition manually in each translation unit as needed (if you choose to use the shorter namespace notation at all). +</> + +</section> + +&metafunctions; +&if; +&applyif; +&applyif2; + +</section> \ No newline at end of file diff --git a/preprocessed/pp.py b/preprocessed/pp.py new file mode 100644 index 0000000..32365bf --- /dev/null +++ b/preprocessed/pp.py @@ -0,0 +1,202 @@ +import fileinput +import os +import re +import string +import sys + +if_else = lambda a,b,c:(a and [b] or [c])[0] +max_len = 79 +ident = 4 + +def nearest_ident_pos(text): + return (len(text)/ident) * ident + +def block_format(limits,text,first_sep=' ',sep=',',need_last_ident=1): + words = string.split( + string.join(string.split(text),' ') + , if_else(sep != ',' or string.find(text,'<') == -1,sep,' %s '%sep) + ) + s = reduce(lambda t,x: '%s '%t, range(0,limits[0]), '') + max_len = limits[1] + return '%s\n%s' \ + % ( + reduce( + lambda t,w,max_len=max_len,s=s,sep=sep: + if_else(t[1] + len(w) < max_len + , ('%s%s%s'% (t[0],t[2],w), t[1]+len(w)+len(t[2]), sep) + , ('%s\n%s%s%s'% (t[0],s,sep,w), len(s)+len(w)+len(sep), sep) + ) + , words + , (s,len(s)+len(first_sep),first_sep) + )[0] + , if_else(need_last_ident,s,'') + ) + +def handle_args(match): + if re.compile('^\s*(typedef|struct|static)\s+.*?$').match(match.group(0)): + return match.group(0) + + return '%s'\ + % block_format( + (nearest_ident_pos(match.group(1)),max_len) + , match.group(3) + , match.group(2) + , ',' + , 0 + ) + +def handle_inline_args(match): + if len(match.group(0)) < max_len: + return match.group(0) + + if match.group(9) == None: + return '%s%s<\n%s>\n'\ + % ( + match.group(1) + , match.group(3) + , block_format( + (nearest_ident_pos(match.group(1))+ident,max_len) + , match.group(4) + ) + ) + + return '%s%s<\n%s>\n%s%s'\ + % ( + match.group(1) + , match.group(3) + , block_format( + (nearest_ident_pos(match.group(1))+ident,max_len-len(match.group(9))) + , match.group(4) + ) + , string.replace(match.group(1),',',' ') + , match.group(9) + ) + +def handle_simple_list(match): + if match.group(1) == 'template': + return match.group(0) + + single_arg = re.compile('^\s*(\w|\d)+\s*$').match(match.group(2)) + return if_else(single_arg,'%s<%s>','%s< %s >') %\ + ( + match.group(1) + , string.join(string.split(match.group(2)), '') + ) + +def handle_static(match): + if len(match.group(0)) < max_len: + return match.group(0) + + (first_sep,sep) = if_else(string.find(match.group(0),'+') == -1, (' ',' '),(' ','+')) + return '%s%s\n%s%s' %\ + ( + match.group(1) + , string.join(string.split(match.group(2)), ' ') + , block_format( + (nearest_ident_pos(match.group(1))+ident,max_len) + , match.group(4) + , first_sep + , sep + ) + , match.group(5) + ) + +def handle_typedefs(match): + if string.count(match.group(2), ';') == 1: + return match.group(0) + + join_sep = ';\n%s' % match.group(1) +# return if_else(string.find(match.group(0), '\n') == -1, '%s%s\n', '%s%s') \ + return '%s%s\n' \ + % ( + match.group(1) + , string.join(map(string.strip, string.split(match.group(2), ';')), join_sep) + ) + +class pretty: + def __init__(self, name): + self.output = open(name, "w") + self.prev_line = '' + + self.re_header_name_comment = re.compile(r"^\s*//\s*boost\s+(mpl(/\w+)+\.hpp)\s+header\s+file\s*$") + self.header_was_written = 0 + + self.re_junk = re.compile(r"^\s*(#|//[^:]).*$") + self.re_c_comment_start = re.compile(r"^\s*/\*.*") + self.re_c_comment_end = re.compile(r"^.*\*/\s*$") + self.inside_c_comment = 0 + + self.re_empty_line = re.compile(r"^\s*$") + self.re_comma = re.compile(r'(\w+)\s*,\s*') + self.re_assign = re.compile(r'\s*(=+)\s*') + self.re_marked_comment = re.compile(r'^(\s*//):(.*)$') + self.re_marked_empty_comment = re.compile(r'^\s*//\s*$') + self.re_typedef = re.compile(r'^\s+typedef\s+.*?;$') + self.re_nsl = re.compile(r'^(\s+typedef\s+.*?;|\s*(private|public):\s*|\s*{\s*|\s*(\w|\d|,)+\s*)$') + self.re_templ_decl = re.compile(r'^(\s*template\s*<\s*.*?|\s*(private|public):\s*)$') + self.re_type_const = re.compile(r'(const)\s+((unsigned|signed)?(bool|char|short|int|long))') + self.re_templ_args = re.compile(r'(\s*)(, | {2})((\s*(\w+)(\s+|::)\w+\s*.*?,?)+)\s*$') + self.re_inline_templ_args = re.compile( + r'^(\s+(,|:\s+)?|struct\s+)(\w+)\s*<((\s*(typename\s+)?\w+\s*(=\s*.*|<(\s*\w+\s*,?)+>\s*)?,?)+)\s*>\s+((struct|class).*?)?$' + ) + + self.re_simple_list = re.compile(r'(\w+)\s*<((\w|,| |-|>|<)+)>') + self.re_static_const = re.compile(r'(\s*)((static\s+.*?|enum\s*{\s*)value\s*=)(.*?)(}?;)$') + self.re_typedefs = re.compile(r'(\s*)((\s*typedef\s*.*?;)+)\s*$') + + def process(self, line): + + # searching for header line + if not self.header_was_written and self.re_header_name_comment.match(line): + self.header_was_written = 1 + match = self.re_header_name_comment.match(line) + self.output.write( \ + "// preprocessed version of 'boost/%s' header\n"\ + "// see the original for copyright information\n\n" \ + % match.group(1) + ) + return + + # skipping preprocessor directives, comments, etc. + if self.re_junk.match(line): + return + + if self.inside_c_comment or self.re_c_comment_start.match(line): + self.inside_c_comment = not self.re_c_comment_end.match(line) + return + + # restoring some empty lines + if self.re_templ_decl.match(line) and self.re_typedef.match(self.prev_line): + line = '\n%s' % line + + # removing excessive empty lines + if self.re_empty_line.match(line): + if self.re_empty_line.match(self.prev_line) or not self.header_was_written: + return + + # skip empty line after typedef + if self.re_nsl.match(self.prev_line): + return + + # formatting + line = self.re_comma.sub(r'\1, ', line) + line = self.re_assign.sub(r' \1 ', line) + line = self.re_marked_comment.sub(r'\1\2', line) + line = self.re_marked_empty_comment.sub(r'\n', line) + line = self.re_type_const.sub(r'\2 \1', line) + line = self.re_templ_args.sub(handle_args, line) + line = self.re_inline_templ_args.sub(handle_inline_args, line) + line = self.re_simple_list.sub(handle_simple_list, line) + line = self.re_static_const.sub(handle_static, line) + line = self.re_typedefs.sub(handle_typedefs, line) + + # write the output + self.output.write(line) + self.prev_line = line + +def main(): + p = pretty(os.path.basename(sys.argv[2])) + for line in fileinput.input(sys.argv[1]): + p.process(line) + +main() diff --git a/preprocessed/src/advance_backward.cpp b/preprocessed/src/advance_backward.cpp new file mode 100644 index 0000000..ce46b00 --- /dev/null +++ b/preprocessed/src/advance_backward.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/advance_backward.hpp" diff --git a/preprocessed/src/advance_forward.cpp b/preprocessed/src/advance_forward.cpp new file mode 100644 index 0000000..242148f --- /dev/null +++ b/preprocessed/src/advance_forward.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/advance_forward.hpp" diff --git a/preprocessed/src/apply.cpp b/preprocessed/src/apply.cpp new file mode 100644 index 0000000..7ea363b --- /dev/null +++ b/preprocessed/src/apply.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/apply.hpp" diff --git a/preprocessed/src/arg.cpp b/preprocessed/src/arg.cpp new file mode 100644 index 0000000..7518eb4 --- /dev/null +++ b/preprocessed/src/arg.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/arg.hpp" diff --git a/preprocessed/src/basic_bind.cpp b/preprocessed/src/basic_bind.cpp new file mode 100644 index 0000000..af4b77a --- /dev/null +++ b/preprocessed/src/basic_bind.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_NO_UNNAMED_PLACEHOLDER_SUPPORT +#include "boost/mpl/bind.hpp" diff --git a/preprocessed/src/bind.cpp b/preprocessed/src/bind.cpp new file mode 100644 index 0000000..385230f --- /dev/null +++ b/preprocessed/src/bind.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/bind.hpp" diff --git a/preprocessed/src/fold_backward_impl.cpp b/preprocessed/src/fold_backward_impl.cpp new file mode 100644 index 0000000..5923ae6 --- /dev/null +++ b/preprocessed/src/fold_backward_impl.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/fold_backward_impl.hpp" diff --git a/preprocessed/src/fold_impl.cpp b/preprocessed/src/fold_impl.cpp new file mode 100644 index 0000000..a54f9d7 --- /dev/null +++ b/preprocessed/src/fold_impl.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/fold_impl.hpp" diff --git a/preprocessed/src/full_lambda.cpp b/preprocessed/src/full_lambda.cpp new file mode 100644 index 0000000..b4f112e --- /dev/null +++ b/preprocessed/src/full_lambda.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +//#define BOOST_MPL_NO_LAMBDA_HEURISTIC +#include "boost/mpl/aux_/full_lambda.hpp" diff --git a/preprocessed/src/iter_fold_backward_impl.cpp b/preprocessed/src/iter_fold_backward_impl.cpp new file mode 100644 index 0000000..db93b14 --- /dev/null +++ b/preprocessed/src/iter_fold_backward_impl.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/iter_fold_backward_impl.hpp" diff --git a/preprocessed/src/iter_fold_if_impl.cpp b/preprocessed/src/iter_fold_if_impl.cpp new file mode 100644 index 0000000..c883c22 --- /dev/null +++ b/preprocessed/src/iter_fold_if_impl.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/iter_fold_if_impl.hpp" diff --git a/preprocessed/src/iter_fold_impl.cpp b/preprocessed/src/iter_fold_impl.cpp new file mode 100644 index 0000000..c54140f --- /dev/null +++ b/preprocessed/src/iter_fold_impl.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/iter_fold_impl.hpp" diff --git a/preprocessed/src/lambda_helper.cpp b/preprocessed/src/lambda_helper.cpp new file mode 100644 index 0000000..b3d3823 --- /dev/null +++ b/preprocessed/src/lambda_helper.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/lambda_helper.hpp" diff --git a/preprocessed/src/lambda_no_ctps.cpp b/preprocessed/src/lambda_no_ctps.cpp new file mode 100644 index 0000000..f4fece4 --- /dev/null +++ b/preprocessed/src/lambda_no_ctps.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/aux_/lambda_no_ctps.hpp" diff --git a/preprocessed/src/list.cpp b/preprocessed/src/list.cpp new file mode 100644 index 0000000..245fc04 --- /dev/null +++ b/preprocessed/src/list.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list.hpp" diff --git a/preprocessed/src/list10.cpp b/preprocessed/src/list10.cpp new file mode 100644 index 0000000..0754874 --- /dev/null +++ b/preprocessed/src/list10.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list10.hpp" diff --git a/preprocessed/src/list10_c.cpp b/preprocessed/src/list10_c.cpp new file mode 100644 index 0000000..e3ac6bb --- /dev/null +++ b/preprocessed/src/list10_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list10_c.hpp" diff --git a/preprocessed/src/list20.cpp b/preprocessed/src/list20.cpp new file mode 100644 index 0000000..2f4ec33 --- /dev/null +++ b/preprocessed/src/list20.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list20.hpp" diff --git a/preprocessed/src/list20_c.cpp b/preprocessed/src/list20_c.cpp new file mode 100644 index 0000000..ee65fb9 --- /dev/null +++ b/preprocessed/src/list20_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list20_c.hpp" diff --git a/preprocessed/src/list30.cpp b/preprocessed/src/list30.cpp new file mode 100644 index 0000000..f208f02 --- /dev/null +++ b/preprocessed/src/list30.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list30.hpp" diff --git a/preprocessed/src/list30_c.cpp b/preprocessed/src/list30_c.cpp new file mode 100644 index 0000000..740ee28 --- /dev/null +++ b/preprocessed/src/list30_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list30_c.hpp" diff --git a/preprocessed/src/list40.cpp b/preprocessed/src/list40.cpp new file mode 100644 index 0000000..e762c2a --- /dev/null +++ b/preprocessed/src/list40.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list40.hpp" diff --git a/preprocessed/src/list40_c.cpp b/preprocessed/src/list40_c.cpp new file mode 100644 index 0000000..7a21bdd --- /dev/null +++ b/preprocessed/src/list40_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list40_c.hpp" diff --git a/preprocessed/src/list50.cpp b/preprocessed/src/list50.cpp new file mode 100644 index 0000000..fe96b41 --- /dev/null +++ b/preprocessed/src/list50.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list50.hpp" diff --git a/preprocessed/src/list50_c.cpp b/preprocessed/src/list50_c.cpp new file mode 100644 index 0000000..14df78c --- /dev/null +++ b/preprocessed/src/list50_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list/list50_c.hpp" diff --git a/preprocessed/src/list_c.cpp b/preprocessed/src/list_c.cpp new file mode 100644 index 0000000..cf675a3 --- /dev/null +++ b/preprocessed/src/list_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/list_c.hpp" diff --git a/preprocessed/src/lite_vector10.cpp b/preprocessed/src/lite_vector10.cpp new file mode 100644 index 0000000..d55eb59 --- /dev/null +++ b/preprocessed/src/lite_vector10.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector10.hpp" diff --git a/preprocessed/src/lite_vector10_c.cpp b/preprocessed/src/lite_vector10_c.cpp new file mode 100644 index 0000000..315a82c --- /dev/null +++ b/preprocessed/src/lite_vector10_c.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector10_c.hpp" diff --git a/preprocessed/src/lite_vector20.cpp b/preprocessed/src/lite_vector20.cpp new file mode 100644 index 0000000..7bed4b3 --- /dev/null +++ b/preprocessed/src/lite_vector20.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector20.hpp" diff --git a/preprocessed/src/lite_vector20_c.cpp b/preprocessed/src/lite_vector20_c.cpp new file mode 100644 index 0000000..79567d6 --- /dev/null +++ b/preprocessed/src/lite_vector20_c.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector20_c.hpp" diff --git a/preprocessed/src/lite_vector30.cpp b/preprocessed/src/lite_vector30.cpp new file mode 100644 index 0000000..187f201 --- /dev/null +++ b/preprocessed/src/lite_vector30.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector30.hpp" diff --git a/preprocessed/src/lite_vector30_c.cpp b/preprocessed/src/lite_vector30_c.cpp new file mode 100644 index 0000000..8c0ab5e --- /dev/null +++ b/preprocessed/src/lite_vector30_c.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector30_c.hpp" diff --git a/preprocessed/src/lite_vector40.cpp b/preprocessed/src/lite_vector40.cpp new file mode 100644 index 0000000..0e1da21 --- /dev/null +++ b/preprocessed/src/lite_vector40.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector40.hpp" diff --git a/preprocessed/src/lite_vector40_c.cpp b/preprocessed/src/lite_vector40_c.cpp new file mode 100644 index 0000000..882e288 --- /dev/null +++ b/preprocessed/src/lite_vector40_c.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector40_c.hpp" diff --git a/preprocessed/src/lite_vector50.cpp b/preprocessed/src/lite_vector50.cpp new file mode 100644 index 0000000..b30e146 --- /dev/null +++ b/preprocessed/src/lite_vector50.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector50.hpp" diff --git a/preprocessed/src/lite_vector50_c.cpp b/preprocessed/src/lite_vector50_c.cpp new file mode 100644 index 0000000..96ef271 --- /dev/null +++ b/preprocessed/src/lite_vector50_c.cpp @@ -0,0 +1,3 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#define BOOST_MPL_TYPEOF_BASED_VECTOR_IMPL +#include "boost/mpl/vector/vector50_c.hpp" diff --git a/preprocessed/src/meta_fun.cpp b/preprocessed/src/meta_fun.cpp new file mode 100644 index 0000000..646a153 --- /dev/null +++ b/preprocessed/src/meta_fun.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/meta_fun.hpp" diff --git a/preprocessed/src/placeholder.cpp b/preprocessed/src/placeholder.cpp new file mode 100644 index 0000000..5c5bca7 --- /dev/null +++ b/preprocessed/src/placeholder.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/placeholder.hpp" diff --git a/preprocessed/src/vector.cpp b/preprocessed/src/vector.cpp new file mode 100644 index 0000000..9c8b52a --- /dev/null +++ b/preprocessed/src/vector.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector.hpp" diff --git a/preprocessed/src/vector10.cpp b/preprocessed/src/vector10.cpp new file mode 100644 index 0000000..f8f3fec --- /dev/null +++ b/preprocessed/src/vector10.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector10.hpp" diff --git a/preprocessed/src/vector10_c.cpp b/preprocessed/src/vector10_c.cpp new file mode 100644 index 0000000..31bdbf8 --- /dev/null +++ b/preprocessed/src/vector10_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector10_c.hpp" diff --git a/preprocessed/src/vector20.cpp b/preprocessed/src/vector20.cpp new file mode 100644 index 0000000..c6f8138 --- /dev/null +++ b/preprocessed/src/vector20.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector20.hpp" diff --git a/preprocessed/src/vector20_c.cpp b/preprocessed/src/vector20_c.cpp new file mode 100644 index 0000000..c5cef1e --- /dev/null +++ b/preprocessed/src/vector20_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector20_c.hpp" diff --git a/preprocessed/src/vector30.cpp b/preprocessed/src/vector30.cpp new file mode 100644 index 0000000..86f9d98 --- /dev/null +++ b/preprocessed/src/vector30.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector30.hpp" diff --git a/preprocessed/src/vector30_c.cpp b/preprocessed/src/vector30_c.cpp new file mode 100644 index 0000000..724ae4f --- /dev/null +++ b/preprocessed/src/vector30_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector30_c.hpp" diff --git a/preprocessed/src/vector40.cpp b/preprocessed/src/vector40.cpp new file mode 100644 index 0000000..bc9610a --- /dev/null +++ b/preprocessed/src/vector40.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector40.hpp" diff --git a/preprocessed/src/vector40_c.cpp b/preprocessed/src/vector40_c.cpp new file mode 100644 index 0000000..239e15e --- /dev/null +++ b/preprocessed/src/vector40_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector40_c.hpp" diff --git a/preprocessed/src/vector50.cpp b/preprocessed/src/vector50.cpp new file mode 100644 index 0000000..302d43d --- /dev/null +++ b/preprocessed/src/vector50.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector50.hpp" diff --git a/preprocessed/src/vector50_c.cpp b/preprocessed/src/vector50_c.cpp new file mode 100644 index 0000000..a460f4b --- /dev/null +++ b/preprocessed/src/vector50_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector/vector50_c.hpp" diff --git a/preprocessed/src/vector_c.cpp b/preprocessed/src/vector_c.cpp new file mode 100644 index 0000000..1bbeff4 --- /dev/null +++ b/preprocessed/src/vector_c.cpp @@ -0,0 +1,2 @@ +#define BOOST_MPL_PREPROCESSING_MODE +#include "boost/mpl/vector_c.hpp" diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..a10cf54 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,58 @@ +subproject libs/mpl/test ; + +# bring in rules for testing +SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; +include testing.jam ; + +compile advance.cpp ; +compile always.cpp ; +compile apply.cpp ; +compile apply_if.cpp ; +compile arithmetic.cpp ; +compile assert_is_same.cpp ; +compile at.cpp ; +compile back.cpp ; +compile bind.cpp ; +compile bool_c.cpp ; +compile comparison.cpp ; +compile copy.cpp ; +compile copy_backward.cpp ; +compile copy_backward_if.cpp ; +compile copy_if.cpp ; +compile count.cpp ; +compile count_if.cpp ; +compile distance.cpp ; +compile empty.cpp ; +compile equal.cpp ; +compile erase.cpp ; +compile erase_range.cpp ; +compile filter_view.cpp ; +compile find.cpp ; +compile find_if.cpp ; +compile for_each.cpp ; +compile front.cpp ; +compile identity.cpp ; +compile if.cpp ; +compile insert.cpp ; +compile insert_range.cpp ; +compile int_c.cpp ; +compile integral_c.cpp ; +compile lambda.cpp ; +compile list.cpp ; +compile list_c.cpp ; +compile logical.cpp ; +compile lower_bound.cpp ; +compile meta_fun.cpp ; +compile next.cpp ; +compile pop_front.cpp ; +compile push_front.cpp ; +compile range_c.cpp ; +compile replace.cpp ; +compile replace_if.cpp ; +compile reverse.cpp ; +compile size.cpp ; +compile size_of.cpp ; +compile transform.cpp ; +compile transform_view.cpp ; +compile unique.cpp ; +compile upper_bound.cpp ; diff --git a/test/advance.cpp b/test/advance.cpp new file mode 100644 index 0000000..8fec7c7 --- /dev/null +++ b/test/advance.cpp @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/advance.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/vector/vector10_c.hpp" +#include "boost/mpl/advance.hpp" +#include "boost/mpl/begin_end.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::vector10_c<int,0,1,2,3,4,5,6,7,8,9> numbers; + typedef mpl::begin<numbers>::type first; + typedef mpl::end<numbers>::type last; + + typedef mpl::advance_c<first,10>::type iter1; + typedef mpl::advance_c<last,-10>::type iter2; + + BOOST_MPL_ASSERT_IS_SAME(iter1, last); + BOOST_MPL_ASSERT_IS_SAME(iter2, first); + + return 0; +} diff --git a/test/always.cpp b/test/always.cpp new file mode 100644 index 0000000..bf687d7 --- /dev/null +++ b/test/always.cpp @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/always.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/always.hpp" +#include "boost/mpl/bool_c.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/apply.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::always<mpl::true_c> always_true; + typedef mpl::apply1< always_true,mpl::false_c >::type res1; + typedef mpl::apply2< always_true,mpl::false_c,mpl::false_c >::type res2; + typedef mpl::apply3< always_true,mpl::false_c,mpl::false_c,mpl::false_c >::type res3; + + BOOST_STATIC_ASSERT(res1::value == true); + BOOST_STATIC_ASSERT(res2::value == true); + BOOST_STATIC_ASSERT(res3::value == true); + + typedef mpl::always< mpl::int_c<10> > always_10; + typedef mpl::apply1< always_10,mpl::int_c<0> >::type res4; + typedef mpl::apply2< always_10,mpl::int_c<0>,mpl::int_c<0> >::type res5; + typedef mpl::apply3< always_10,mpl::int_c<0>,mpl::int_c<0>,mpl::int_c<0> >::type res6; + + BOOST_STATIC_ASSERT(res4::value == 10); + BOOST_STATIC_ASSERT(res5::value == 10); + BOOST_STATIC_ASSERT(res6::value == 10); + + return 0; +} diff --git a/test/apply.cpp b/test/apply.cpp new file mode 100644 index 0000000..0e9b43d --- /dev/null +++ b/test/apply.cpp @@ -0,0 +1,115 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/apply.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/apply.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/mpl/limits/arity.hpp" +#include "boost/mpl/aux_/preprocessor/params.hpp" +#include "boost/mpl/aux_/preprocessor/enum.hpp" +#include "boost/mpl/aux_/preprocessor/project1st.hpp" + +#include "boost/preprocessor/repeat_2nd.hpp" +#include "boost/preprocessor/comma_if.hpp" +#include "boost/preprocessor/dec.hpp" +#include "boost/preprocessor/if.hpp" +#include "boost/preprocessor/cat.hpp" + +namespace mpl = boost::mpl; + +#define APPLY_0_FUNC_DEF(i) \ + struct f0 { typedef char type; }; \ +/**/ + +#define APPLY_N_FUNC_DEF(i) \ + struct first##i \ + { \ + template< BOOST_MPL_PP_PARAMS(i, typename U) > \ + struct apply { typedef U1 type; }; \ + }; \ + \ + struct last##i \ + { \ + template< BOOST_MPL_PP_PARAMS(i, typename U) > \ + struct apply { typedef BOOST_PP_CAT(U,i) type; }; \ + }; \ +/**/ + +#define APPLY_FUNC_DEF(z, i, unused) \ + BOOST_PP_IF( \ + i \ + , APPLY_N_FUNC_DEF \ + , APPLY_0_FUNC_DEF \ + )(i) \ +/**/ + +namespace aux { +BOOST_PP_REPEAT_2ND( + BOOST_MPL_METAFUNCTION_MAX_ARITY + , APPLY_FUNC_DEF + , unused + ) +} + +#define APPLY_0_TEST(i, apply_) \ + typedef mpl::apply_<aux::f##i>::type t; \ + { BOOST_MPL_ASSERT_IS_SAME(t, char); } \ +/**/ + +#define APPLY_N_TEST(i, apply_) \ + typedef mpl::apply_< \ + aux::first##i \ + , char \ + BOOST_PP_COMMA_IF(BOOST_PP_DEC(i)) \ + BOOST_MPL_PP_ENUM(BOOST_PP_DEC(i), int) \ + >::type t1; \ + \ + typedef mpl::apply_< \ + aux::last##i \ + , BOOST_MPL_PP_ENUM(BOOST_PP_DEC(i), int) \ + BOOST_PP_COMMA_IF(BOOST_PP_DEC(i)) char \ + >::type t2; \ + { BOOST_MPL_ASSERT_IS_SAME(t1, char); } \ + { BOOST_MPL_ASSERT_IS_SAME(t2, char); } \ +/**/ + +#define APPLY_TEST(z, i, APPLY_NAME) \ + BOOST_PP_IF( \ + i \ + , APPLY_N_TEST \ + , APPLY_0_TEST \ + )(i, APPLY_NAME(i)) \ +/**/ + +#define MAKE_APPLY_N_NAME(i) apply##i +#define MAKE_APPLY_NAME(i) apply + +int main() +{ + BOOST_PP_REPEAT_2ND( + BOOST_MPL_METAFUNCTION_MAX_ARITY + , APPLY_TEST + , MAKE_APPLY_N_NAME + ) + +#if defined(BOOST_MPL_HAS_APPLY) + BOOST_PP_REPEAT_2ND( + BOOST_MPL_METAFUNCTION_MAX_ARITY + , APPLY_TEST + , MAKE_APPLY_NAME + ) +#endif + return 0; +} diff --git a/test/apply_if.cpp b/test/apply_if.cpp new file mode 100644 index 0000000..cb44479 --- /dev/null +++ b/test/apply_if.cpp @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/apply_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/apply_if.hpp" +#include "boost/mpl/bool_c.hpp" +#include "boost/mpl/identity.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::apply_if< + mpl::true_c + , mpl::identity<char> + , mpl::identity<long> + >::type t1; + + typedef mpl::apply_if_c< + true + , mpl::identity<char> + , mpl::identity<long> + >::type t2; + + BOOST_MPL_ASSERT_IS_SAME(t1, char); + BOOST_MPL_ASSERT_IS_SAME(t2, char); + + typedef mpl::apply_if< + mpl::false_c + , mpl::identity<char> + , mpl::identity<long> + >::type t3; + + typedef mpl::apply_if_c< + false + , mpl::identity<char> + , mpl::identity<long> + >::type t4; + + BOOST_MPL_ASSERT_IS_SAME(t3, long); + BOOST_MPL_ASSERT_IS_SAME(t4, long); + + return 0; +} diff --git a/test/arithmetic.cpp b/test/arithmetic.cpp new file mode 100644 index 0000000..29d7779 --- /dev/null +++ b/test/arithmetic.cpp @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/arithmetic.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/arithmetic.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::int_c<0> _0; + typedef mpl::int_c<1> _1; + typedef mpl::int_c<3> _3; + typedef mpl::int_c<10> _10; + + BOOST_STATIC_ASSERT((mpl::plus<_0,_10>::value == 10)); + BOOST_STATIC_ASSERT((mpl::plus<_10,_0>::value == 10)); + + BOOST_STATIC_ASSERT((mpl::minus<_0,_10>::value == -10)); + BOOST_STATIC_ASSERT((mpl::minus<_10,_0>::value == 10)); + + BOOST_STATIC_ASSERT((mpl::multiplies<_1,_10>::value == 10)); + BOOST_STATIC_ASSERT((mpl::multiplies<_10,_1>::value == 10)); + + BOOST_STATIC_ASSERT((mpl::divides<_10,_1>::value == 10)); + BOOST_STATIC_ASSERT((mpl::divides<_10,_1>::value == 10)); + + BOOST_STATIC_ASSERT((mpl::modulus<_10,_1>::value == 0)); + BOOST_STATIC_ASSERT((mpl::modulus<_10,_3>::value == 1)); + + BOOST_STATIC_ASSERT((mpl::minus<_10,_1,_10>::value == -1)); + BOOST_STATIC_ASSERT((mpl::plus<_10,_1,_10>::value == 21)); + BOOST_STATIC_ASSERT((mpl::divides<_10,_1,_10>::value == 1)); + BOOST_STATIC_ASSERT((mpl::divides<_10,_1,_10>::value == 1)); + + BOOST_STATIC_ASSERT((mpl::negate<_10>::value == -10)); + + return 0; +} diff --git a/test/assert_is_same.cpp b/test/assert_is_same.cpp new file mode 100644 index 0000000..5241c24 --- /dev/null +++ b/test/assert_is_same.cpp @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/assert_is_same.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/assert_is_same.hpp" + +namespace { +struct my; +} + +int main() +{ + BOOST_MPL_ASSERT_IS_SAME(long, long); + BOOST_MPL_ASSERT_IS_SAME(my, my); + + BOOST_MPL_ASSERT_NOT_SAME(my, long); + BOOST_MPL_ASSERT_NOT_SAME(long, my); + + return 0; +} diff --git a/test/at.cpp b/test/at.cpp new file mode 100644 index 0000000..c2a9dee --- /dev/null +++ b/test/at.cpp @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/at.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/at.hpp" +#include "boost/mpl/vector/vector10_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::vector10_c<int,9,8,7,6,5,4,3,2,1,0> numbers; + + BOOST_STATIC_ASSERT((mpl::at_c<0, numbers>::type::value == 9)); + BOOST_STATIC_ASSERT((mpl::at_c<1, numbers>::type::value == 8)); + BOOST_STATIC_ASSERT((mpl::at_c<2, numbers>::type::value == 7)); + BOOST_STATIC_ASSERT((mpl::at_c<3, numbers>::type::value == 6)); + BOOST_STATIC_ASSERT((mpl::at_c<4, numbers>::type::value == 5)); + BOOST_STATIC_ASSERT((mpl::at_c<5, numbers>::type::value == 4)); + BOOST_STATIC_ASSERT((mpl::at_c<6, numbers>::type::value == 3)); + BOOST_STATIC_ASSERT((mpl::at_c<7, numbers>::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::at_c<8, numbers>::type::value == 1)); + BOOST_STATIC_ASSERT((mpl::at_c<9, numbers>::type::value == 0)); + + return 0; +} diff --git a/test/back.cpp b/test/back.cpp new file mode 100644 index 0000000..b9855fd --- /dev/null +++ b/test/back.cpp @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/back.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/back.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::range_c<int,0,1> range1; + typedef mpl::range_c<int,0,10> range2; + typedef mpl::range_c<int,-10,0> range3; + + BOOST_STATIC_ASSERT(mpl::back<range1>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::back<range2>::type::value == 9); + BOOST_STATIC_ASSERT(mpl::back<range3>::type::value == -1); + + return 0; +} diff --git a/test/bind.cpp b/test/bind.cpp new file mode 100644 index 0000000..3008054 --- /dev/null +++ b/test/bind.cpp @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/bind.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Peter Dimov, Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/bind.hpp" +#include "boost/mpl/apply.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/type_traits/is_same.hpp" + +namespace mpl = boost::mpl; + +namespace { + +struct f1 +{ + template< typename T1 > struct apply + { + typedef T1 type; + }; +}; + +struct f5 +{ + template< typename T1, typename T2, typename T3, typename T4, typename T5 > + struct apply + { + typedef T5 type; + }; +}; + +} // namespace + +int main() +{ + using namespace mpl::placeholder; + + typedef mpl::apply1< mpl::bind1<f1,_1>,int >::type r11; + typedef mpl::apply5< mpl::bind1<f1,_5>,void,void,void,void,int >::type r12; + BOOST_MPL_ASSERT_IS_SAME(r11,int); + BOOST_MPL_ASSERT_IS_SAME(r12,int); + + typedef mpl::apply5< mpl::bind5<f5,_1,_2,_3,_4,_5>,void,void,void,void,int >::type r51; + typedef mpl::apply5< mpl::bind5<f5,_5,_4,_3,_2,_1>,int,void,void,void,void >::type r52; + BOOST_MPL_ASSERT_IS_SAME(r51,int); + BOOST_MPL_ASSERT_IS_SAME(r52,int); + + return 0; +} diff --git a/test/bool_c.cpp b/test/bool_c.cpp new file mode 100644 index 0000000..6949b59 --- /dev/null +++ b/test/bool_c.cpp @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/bool_c.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/bool_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +#include <cassert> + +namespace mpl = boost::mpl; + +#define BOOL_C_TEST(c) \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::bool_c<c>::value_type, bool); } \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::bool_c<c>, mpl::c##_c); } \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::bool_c<c>::type, mpl::bool_c<c>); } \ + { BOOST_STATIC_ASSERT(mpl::bool_c<c>::value == c); } \ + assert(mpl::bool_c<c>() == c); \ +/**/ + +int main() +{ + BOOL_C_TEST(true) + BOOL_C_TEST(false) + return 0; +} diff --git a/test/comparison.cpp b/test/comparison.cpp new file mode 100644 index 0000000..f5404b9 --- /dev/null +++ b/test/comparison.cpp @@ -0,0 +1,53 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/comparison.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/comparison.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::int_c<0> _0; + typedef mpl::int_c<10> _10; + + BOOST_STATIC_ASSERT((mpl::less<_0, _10>::value)); + BOOST_STATIC_ASSERT((!mpl::less<_10, _0>::value)); + BOOST_STATIC_ASSERT((!mpl::less<_10, _10>::value)); + + BOOST_STATIC_ASSERT((mpl::less_equal<_0, _10>::value)); + BOOST_STATIC_ASSERT((!mpl::less_equal<_10, _0>::value)); + BOOST_STATIC_ASSERT((mpl::less_equal<_10, _10>::value)); + + BOOST_STATIC_ASSERT((mpl::greater<_10, _0>::value)); + BOOST_STATIC_ASSERT((!mpl::greater<_0, _10>::value)); + BOOST_STATIC_ASSERT((!mpl::greater<_10, _10>::value)); + + BOOST_STATIC_ASSERT((!mpl::greater_equal<_0, _10>::value)); + BOOST_STATIC_ASSERT((mpl::greater_equal<_10, _0>::value)); + BOOST_STATIC_ASSERT((mpl::greater_equal<_10, _10>::value)); + + BOOST_STATIC_ASSERT((!mpl::equal_to<_0, _10>::value)); + BOOST_STATIC_ASSERT((!mpl::equal_to<_10, _0>::value)); + BOOST_STATIC_ASSERT((mpl::equal_to<_10, _10>::value)); + + BOOST_STATIC_ASSERT((mpl::not_equal_to<_0, _10>::value)); + BOOST_STATIC_ASSERT((mpl::not_equal_to<_10, _0>::value)); + BOOST_STATIC_ASSERT((!mpl::not_equal_to<_10, _10>::value)); + + return 0; +} diff --git a/test/copy.cpp b/test/copy.cpp new file mode 100644 index 0000000..7f67c1f --- /dev/null +++ b/test/copy.cpp @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/copy.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/copy.hpp" +#include "boost/mpl/vector/vector10_c.hpp" +#include "boost/mpl/vector.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/push_front.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::vector10_c<int,9,8,7,6,5,4,3,2,1,0> answer; + typedef mpl::copy< + mpl::range_c<int,0,10> + , mpl::vector<> + , mpl::push_front<_,_> + >::type result; + + BOOST_STATIC_ASSERT(mpl::size<result>::value == 10); + BOOST_STATIC_ASSERT((mpl::equal< result,answer >::type::value)); + + return 0; +} diff --git a/test/copy_backward.cpp b/test/copy_backward.cpp new file mode 100644 index 0000000..a6fd258 --- /dev/null +++ b/test/copy_backward.cpp @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/copy_backward.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/copy_backward.hpp" +#include "boost/mpl/list/list10_c.hpp" +#include "boost/mpl/push_front.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + + typedef mpl::list10_c<int,10,11,12,13,14,15,16,17,18,19>::type numbers; + typedef mpl::copy_backward< + mpl::range_c<int,0,10> + , numbers + , mpl::push_front<_,_> + >::type result; + + BOOST_STATIC_ASSERT(mpl::size<result>::value == 20); + BOOST_STATIC_ASSERT((mpl::equal< result,mpl::range_c<int,0,20> >::type::value)); + + return 0; +} diff --git a/test/copy_backward_if.cpp b/test/copy_backward_if.cpp new file mode 100644 index 0000000..081f184 --- /dev/null +++ b/test/copy_backward_if.cpp @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/copy_backward_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/copy_backward_if.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/push_front.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/type_traits/is_float.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::list<int,float,long,float,char,long,double,double>::type types; + typedef mpl::list<float,float,double,double>::type float_types; + typedef mpl::copy_backward_if< + types + , mpl::list0<> + , mpl::push_front<_,_> + , boost::is_float<_> + >::type result; + + BOOST_STATIC_ASSERT(mpl::size<result>::value == 4); + BOOST_STATIC_ASSERT((mpl::equal<result,result>::type::value)); + + return 0; +} diff --git a/test/copy_if.cpp b/test/copy_if.cpp new file mode 100644 index 0000000..21cc0d1 --- /dev/null +++ b/test/copy_if.cpp @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/copy_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/copy_if.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/push_front.hpp" +#include "boost/mpl/comparison/less.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/mpl/size.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::list_c<int,0,1,2,3,4,5,6,7,8,9>::type numbers; + typedef mpl::list_c<int,4,3,2,1,0>::type answer; + typedef mpl::copy_if< + numbers + , mpl::list0_c<int> + , mpl::push_front<_,_> + , mpl::less<_,mpl::int_c<5> > + >::type result; + + BOOST_STATIC_ASSERT(mpl::size<result>::value == 5); + BOOST_STATIC_ASSERT((mpl::equal<result,answer>::type::value)); + + return 0; +} diff --git a/test/count.cpp b/test/count.cpp new file mode 100644 index 0000000..b99ea46 --- /dev/null +++ b/test/count.cpp @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/count.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/count.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,char,long,short,char,long,double,long> types; + typedef mpl::list_c<int,1,0,5,1,7,5,0,5> values; + + BOOST_STATIC_ASSERT((mpl::count<types,int>::type::value == 1)); + BOOST_STATIC_ASSERT((mpl::count<types,double>::type::value == 1)); + BOOST_STATIC_ASSERT((mpl::count<types,char>::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::count<types,long>::type::value == 3)); + BOOST_STATIC_ASSERT((mpl::count<types,unsigned>::type::value == 0)); + + BOOST_STATIC_ASSERT((mpl::count< values, mpl::integral_c<int,1> >::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::count< values, mpl::integral_c<int,0> >::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::count< values, mpl::integral_c<int,5> >::type::value == 3)); + BOOST_STATIC_ASSERT((mpl::count< values, mpl::integral_c<int,7> >::type::value == 1)); + BOOST_STATIC_ASSERT((mpl::count< values, mpl::integral_c<int,8> >::type::value == 0)); + + return 0; +} diff --git a/test/count_if.cpp b/test/count_if.cpp new file mode 100644 index 0000000..d629c80 --- /dev/null +++ b/test/count_if.cpp @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/count_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/count_if.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/comparison/less.hpp" +#include "boost/mpl/comparison/equal_to.hpp" +#include "boost/type_traits/is_float.hpp" +#include "boost/type_traits/is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list<int,char,long,short,char,long,double,long> types; + typedef mpl::list_c<int,1,0,5,1,7,5,0,5> values; + + BOOST_STATIC_ASSERT((mpl::count_if< types, boost::is_float<_> >::type::value == 1)); + BOOST_STATIC_ASSERT((mpl::count_if< types, boost::is_same<_,char> >::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::count_if< types, boost::is_same<_,void> >::type::value == 0)); + + BOOST_STATIC_ASSERT((mpl::count_if< values, mpl::lt<5> >::type::value == 4)); + BOOST_STATIC_ASSERT((mpl::count_if< values, mpl::eq<0> >::type::value == 2)); + BOOST_STATIC_ASSERT((mpl::count_if< values, mpl::eq<-1> >::type::value == 0)); + + return 0; +} diff --git a/test/distance.cpp b/test/distance.cpp new file mode 100644 index 0000000..68dda2a --- /dev/null +++ b/test/distance.cpp @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/distance.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/distance.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +void list_distance_test() +{ + typedef mpl::list<char,short,int,long>::type list; + typedef mpl::begin<list>::type first; + typedef mpl::end<list>::type last; + + BOOST_STATIC_ASSERT((mpl::distance<first,last>::type::value == 4)); +} + +void range_distance_test() +{ + typedef mpl::range_c<int,0,10>::type range; + typedef mpl::begin<range>::type first; + typedef mpl::end<range>::type last; + + BOOST_STATIC_ASSERT((mpl::distance<first,last>::type::value == 10)); +} + +int main() +{ + return 0; +} diff --git a/test/empty.cpp b/test/empty.cpp new file mode 100644 index 0000000..db56840 --- /dev/null +++ b/test/empty.cpp @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/empty.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/empty.hpp" +#include "boost/mpl/list/list10.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list0<> list0; + typedef mpl::list1<char> list1; + + BOOST_STATIC_ASSERT((mpl::empty<list0>::type::value == true)); + BOOST_STATIC_ASSERT((mpl::empty<list1>::type::value == false)); + + return 0; +} diff --git a/test/equal.cpp b/test/equal.cpp new file mode 100644 index 0000000..9d54319 --- /dev/null +++ b/test/equal.cpp @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/equal.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/equal.hpp" +#include "boost/mpl/list.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,float,long,double,char,long,double,float> list1; + typedef mpl::list<int,float,long,double,char,long,double,float> list2; + typedef mpl::list<int,float,long,double,char,long,double,short> list3; + typedef mpl::list<int,float,long,double,char,long,double> list4; + + BOOST_STATIC_ASSERT((mpl::equal<list1,list2>::type::value == true)); + BOOST_STATIC_ASSERT((mpl::equal<list2,list1>::type::value == true)); + BOOST_STATIC_ASSERT((mpl::equal<list2,list3>::type::value == false)); + BOOST_STATIC_ASSERT((mpl::equal<list3,list4>::type::value == false)); + BOOST_STATIC_ASSERT((mpl::equal<list4,list3>::type::value == false)); + + return 0; +} diff --git a/test/erase.cpp b/test/erase.cpp new file mode 100644 index 0000000..e8b9792 --- /dev/null +++ b/test/erase.cpp @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/erase.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/erase.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/find.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/integral_c.hpp" +#include "boost/mpl/begin_end.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,char,long,short,char,long,double,long> types; + typedef mpl::list_c<int,1,0,5,1,7,5,0,5> values; + + typedef mpl::find<types,short>::type types_iter; + typedef mpl::find< values, mpl::integral_c<int,7> >::type values_iter; + + typedef mpl::erase<types, types_iter>::type result_types; + typedef mpl::erase<values, values_iter>::type result_values; + + BOOST_STATIC_ASSERT(mpl::size<result_types>::type::value == 7); + BOOST_STATIC_ASSERT(mpl::size<result_values>::type::value == 7); + + typedef mpl::find<result_types,short>::type result_types_iter; + typedef mpl::find<result_values, mpl::integral_c<int,7> >::type result_values_iter; + + BOOST_MPL_ASSERT_IS_SAME(result_types_iter, mpl::end<result_types>::type); + BOOST_MPL_ASSERT_IS_SAME(result_values_iter, mpl::end<result_values>::type); + + return 0; +} diff --git a/test/erase_range.cpp b/test/erase_range.cpp new file mode 100644 index 0000000..d412678 --- /dev/null +++ b/test/erase_range.cpp @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/erase_range.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/erase.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/find.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/begin_end.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" +#include "boost/config.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,char,long,short,unsigned,long,double,long> types; + + typedef mpl::find<types,short>::type iter1; + typedef mpl::find<types,double>::type iter2; + + typedef mpl::erase<types,iter1,iter2>::type result; + + BOOST_STATIC_ASSERT(mpl::size<result>::type::value == 5); + + typedef mpl::find<result,unsigned>::type iter; + BOOST_MPL_ASSERT_IS_SAME(iter, mpl::end<result>::type); + + return 0; +} diff --git a/test/filter_view.cpp b/test/filter_view.cpp new file mode 100644 index 0000000..e246011 --- /dev/null +++ b/test/filter_view.cpp @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/filter_view.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/filter_view.hpp" +#include "boost/mpl/transform_view.hpp" +#include "boost/mpl/max_element.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/size_of.hpp" +#include "boost/type_traits/is_float.hpp" +#include "boost/type_traits/is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::list<int,float,long,float,char[50],long double,char> types; + typedef mpl::max_element< + mpl::transform_view< + mpl::filter_view< types,boost::is_float<_> > + , mpl::size_of<_> + > + >::type iter; + + BOOST_STATIC_ASSERT((boost::is_same<iter::base::type,long double>::value)); + return 0; +} diff --git a/test/find.cpp b/test/find.cpp new file mode 100644 index 0000000..ca23ef7 --- /dev/null +++ b/test/find.cpp @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/find.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/find.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/distance.hpp" +#include "boost/mpl/begin_end.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,char,long,short,char,long,double,long>::type types; + typedef mpl::list_c<int,1,0,5,1,7,5,0,5> values; + + typedef mpl::find<types, short>::type types_iter; + typedef mpl::find< values, mpl::integral_c<int,7> >::type values_iter; + + BOOST_MPL_ASSERT_IS_SAME(types_iter::type, short); + BOOST_STATIC_ASSERT(values_iter::type::value == 7); + + typedef mpl::begin<types>::type types_first; + typedef mpl::begin<values>::type values_first; + BOOST_STATIC_ASSERT((mpl::distance< types_first,types_iter >::type::value == 3)); + BOOST_STATIC_ASSERT((mpl::distance< values_first,values_iter >::type::value == 4)); + + return 0; +} diff --git a/test/find_if.cpp b/test/find_if.cpp new file mode 100644 index 0000000..315a9ec --- /dev/null +++ b/test/find_if.cpp @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/find_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/find_if.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/distance.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/type_traits/is_float.hpp" +#include "boost/type_traits/is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list9<int,char,long,short,char,long,double,float,char>::type types; + + typedef mpl::find_if< types, boost::is_float<_> >::type iter1; + typedef mpl::find_if< types, boost::is_same<_,long> >::type iter2; + typedef mpl::find_if< types, boost::is_same<_,void> >::type iter3; + + BOOST_MPL_ASSERT_IS_SAME(iter1::type, double); + BOOST_MPL_ASSERT_IS_SAME(iter2::type, long); + BOOST_MPL_ASSERT_IS_SAME(iter3, mpl::end<types>::type); + + typedef mpl::begin<types>::type first; + BOOST_STATIC_ASSERT((mpl::distance<first,iter1>::type::value == 6)); + BOOST_STATIC_ASSERT((mpl::distance<first,iter2>::type::value == 2)); + + return 0; +} diff --git a/test/for_each.cpp b/test/for_each.cpp new file mode 100644 index 0000000..8c3a3fb --- /dev/null +++ b/test/for_each.cpp @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/for_each.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/for_each.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/identity.hpp" +#include "boost/mpl/lambda.hpp" +#include "boost/bind.hpp" + +#include <vector> +#include <iostream> +#include <typeinfo> +#include <cassert> + +namespace mpl = boost::mpl; +using mpl::_; + +struct printer +{ + printer(std::ostream& s) : f_stream(&s) {} + template< typename U > void operator()(mpl::identity<U>) + { + *f_stream << typeid(U).name() << '\n'; + } + + private: + std::ostream* f_stream; +}; + +int main() +{ + typedef mpl::list<char,short,int,long,float,double> types; + mpl::for_each< types,mpl::make_identity<_> >(printer(std::cout)); + + typedef mpl::range_c<int,0,10> numbers; + std::vector<int> v; + mpl::for_each<numbers,mpl::_>( + boost::bind(&std::vector<int>::push_back, &v, _1) + ); + + for (int i = 0; i < v.size(); ++i) + assert(v[i] == i); + + return 0; +} diff --git a/test/front.cpp b/test/front.cpp new file mode 100644 index 0000000..0b2b016 --- /dev/null +++ b/test/front.cpp @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/front.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/front.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<long>::type types1; + typedef mpl::list<int,long>::type types2; + typedef mpl::list<char,int,long>::type types3; + + BOOST_MPL_ASSERT_IS_SAME(mpl::front<types1>::type, long); + BOOST_MPL_ASSERT_IS_SAME(mpl::front<types2>::type, int); + BOOST_MPL_ASSERT_IS_SAME(mpl::front<types3>::type, char); + + typedef mpl::list_c<int,1>::type values1; + typedef mpl::list_c<int,2,1>::type values2; + typedef mpl::list_c<int,3,2,1>::type values3; + + BOOST_STATIC_ASSERT(mpl::front<values1>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::front<values2>::type::value == 2); + BOOST_STATIC_ASSERT(mpl::front<values3>::type::value == 3); + + return 0; +} diff --git a/test/identity.cpp b/test/identity.cpp new file mode 100644 index 0000000..71d579e --- /dev/null +++ b/test/identity.cpp @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/identity.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/apply.hpp" +#include "boost/mpl/identity.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::apply1< mpl::identity<>, char >::type t1; + BOOST_MPL_ASSERT_IS_SAME(t1, char); + + return 0; +} diff --git a/test/if.cpp b/test/if.cpp new file mode 100644 index 0000000..3c2a2ed --- /dev/null +++ b/test/if.cpp @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/if.hpp" +#include "boost/mpl/bool_c.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::if_<mpl::true_c,char,long>::type t1; + typedef mpl::if_c<true,char,long>::type t2; + BOOST_MPL_ASSERT_IS_SAME(t1, char); + BOOST_MPL_ASSERT_IS_SAME(t2, char); + + typedef mpl::if_<mpl::false_c,char,long>::type t3; + typedef mpl::if_c<false,char,long>::type t4; + BOOST_MPL_ASSERT_IS_SAME(t3, long); + BOOST_MPL_ASSERT_IS_SAME(t4, long); + + return 0; +} diff --git a/test/insert.cpp b/test/insert.cpp new file mode 100644 index 0000000..8926cb2 --- /dev/null +++ b/test/insert.cpp @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/insert.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/insert.hpp" +#include "boost/mpl/find.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list_c<int,0,1,3,4,5,6,7,8,9> numbers; + typedef mpl::find< numbers,mpl::integral_c<int,3> >::type pos; + typedef mpl::insert< numbers,pos,mpl::integral_c<int,2> >::type range; + + BOOST_STATIC_ASSERT(mpl::size<range>::type::value == 10); + BOOST_STATIC_ASSERT((mpl::equal< range,mpl::range_c<int,0,10> >::type::value)); + return 0; +} diff --git a/test/insert_range.cpp b/test/insert_range.cpp new file mode 100644 index 0000000..066f68e --- /dev/null +++ b/test/insert_range.cpp @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/insert_range.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/insert_range.hpp" +#include "boost/mpl/find.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list_c<int,0,1,7,8,9> numbers; + typedef mpl::find< numbers,mpl::integral_c<int,7> >::type pos; + typedef mpl::insert_range< numbers,pos,mpl::range_c<int,2,7> >::type range; + + BOOST_STATIC_ASSERT(mpl::size<range>::type::value == 10); + BOOST_STATIC_ASSERT((mpl::equal< range,mpl::range_c<int,0,10> >::type::value)); + return 0; +} diff --git a/test/int_c.cpp b/test/int_c.cpp new file mode 100644 index 0000000..020d985 --- /dev/null +++ b/test/int_c.cpp @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/int_c.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" +#include "boost/preprocessor/repeat.hpp" + +#include <cassert> + +namespace mpl = boost::mpl; + +#define INT_C_TEST(z, i, unused) \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::int_c<i>::value_type, int); } \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::int_c<i>::type, mpl::int_c<i>); } \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::int_c<i>::next, mpl::int_c<i+1>); } \ + { BOOST_MPL_ASSERT_IS_SAME(mpl::int_c<i>::prior, mpl::int_c<i-1>); } \ + { BOOST_STATIC_ASSERT(mpl::int_c<i>::value == i); } \ + assert(mpl::int_c<i>() == i); +/**/ + +int main() +{ + BOOST_PP_REPEAT(10, INT_C_TEST, unused) + return 0; +} diff --git a/test/integral_c.cpp b/test/integral_c.cpp new file mode 100644 index 0000000..a1c11e8 --- /dev/null +++ b/test/integral_c.cpp @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/integral_c.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/integral_c.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" +#include "boost/preprocessor/repeat.hpp" + +#include <cassert> + +namespace mpl = boost::mpl; + +#define INTEGRAL_C_TEST(z, i, T) \ + { \ + typedef mpl::integral_c<T,i> c##i; \ + typedef mpl::integral_c<T,i+1> next_c##i; \ + typedef mpl::integral_c<T,i-1> prior_c##i; \ + { BOOST_MPL_ASSERT_IS_SAME(c##i::value_type, T); } \ + { BOOST_MPL_ASSERT_IS_SAME(c##i::type, c##i); } \ + { BOOST_MPL_ASSERT_IS_SAME(c##i::next, next_c##i); } \ + { BOOST_MPL_ASSERT_IS_SAME(c##i::prior, prior_c##i); } \ + { BOOST_STATIC_ASSERT(c##i::value == i); } \ + assert(c##i() == i); \ + } +/**/ + +int main() +{ + BOOST_PP_REPEAT(10, INTEGRAL_C_TEST, char) + BOOST_PP_REPEAT(10, INTEGRAL_C_TEST, short) + BOOST_PP_REPEAT(10, INTEGRAL_C_TEST, int) + return 0; +} diff --git a/test/lambda.cpp b/test/lambda.cpp new file mode 100644 index 0000000..3807996 --- /dev/null +++ b/test/lambda.cpp @@ -0,0 +1,77 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/lambda.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/logical.hpp" +#include "boost/mpl/comparison.hpp" +#include "boost/mpl/lambda.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/bool_c.hpp" +#include "boost/mpl/size_of.hpp" +#include "boost/type_traits/is_same.hpp" +#include "boost/type_traits/is_float.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +struct my +{ + char a[100]; +}; + +int main() +{ + using namespace mpl::placeholder; + + // !(x == char) && !(x == double) && x convertible to int || size_of(x) > 8 + typedef mpl::lambda< + mpl::logical_or< + mpl::logical_and< + mpl::logical_not< boost::is_same<_1, char> > + , mpl::logical_not< boost::is_float<_1> > + > + , mpl::greater< mpl::size_of<_1>, mpl::int_c<8> > + > + >::type f1; + + BOOST_STATIC_ASSERT(!f1::apply<char>::type::value); + BOOST_STATIC_ASSERT(!f1::apply<double>::type::value); + BOOST_STATIC_ASSERT(f1::apply<long>::type::value); + BOOST_STATIC_ASSERT(f1::apply<my>::type::value); + + // x == y || x == my || sizeof(x) == sizeof(y) + typedef mpl::lambda< + mpl::logical_or< + boost::is_same<_1, _2> + , boost::is_same<_2, my> + , mpl::equal_to< mpl::size_of<_1>, mpl::size_of<_2> > + > + >::type f2; + + BOOST_STATIC_ASSERT((!f2::apply<double,char>::type::value)); + BOOST_STATIC_ASSERT((!f2::apply<my,int>::type::value)); + BOOST_STATIC_ASSERT((!f2::apply<my,char[99]>::type::value)); + BOOST_STATIC_ASSERT((f2::apply<int,int>::type::value)); + BOOST_STATIC_ASSERT((f2::apply<my,my>::type::value)); + BOOST_STATIC_ASSERT((f2::apply<signed long, unsigned long>::type::value)); + + // bind <-> lambda interaction + typedef mpl::lambda< mpl::less<_1,_2> >::type pred; + typedef mpl::bind2< pred, _1, mpl::int_c<4> > f3; + + BOOST_STATIC_ASSERT((f3::apply< mpl::int_c<3> >::type::value)); + + return 0; +} diff --git a/test/list.cpp b/test/list.cpp new file mode 100644 index 0000000..7eedceb --- /dev/null +++ b/test/list.cpp @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/list.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/list.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list0<> list0; + typedef mpl::list1<char> list1; + typedef mpl::list2<char,long> list2; + typedef mpl::list9<char,char,char,char,char,char,char,char,char> list9; + + return 0; +} diff --git a/test/list_c.cpp b/test/list_c.cpp new file mode 100644 index 0000000..6b3ef35 --- /dev/null +++ b/test/list_c.cpp @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/list_c.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/front.hpp" +#include "boost/mpl/size.hpp" +#include "boost/static_assert.hpp" +#include "boost/config.hpp" + +namespace mpl = boost::mpl; + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) +void test_bool_list() +{ + typedef mpl::list_c<bool,true>::type list1; + typedef mpl::list_c<bool,false>::type list2; + + BOOST_STATIC_ASSERT(mpl::front<list1>::type::value == true); + BOOST_STATIC_ASSERT(mpl::front<list2>::type::value == false); +} +#endif + +void test_int_list() +{ + typedef mpl::list_c<int,-1>::type list1; + typedef mpl::list_c<int,0,1>::type list2; + typedef mpl::list_c<int,1,2,3>::type list3; + + BOOST_STATIC_ASSERT(mpl::size<list1>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::size<list2>::type::value == 2); + BOOST_STATIC_ASSERT(mpl::size<list3>::type::value == 3); + BOOST_STATIC_ASSERT(mpl::front<list1>::type::value == -1); + BOOST_STATIC_ASSERT(mpl::front<list2>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::front<list3>::type::value == 1); +} + +void test_unsigned_list() +{ + typedef mpl::list_c<unsigned,0>::type list1; + typedef mpl::list_c<unsigned,1,2>::type list2; + + BOOST_STATIC_ASSERT(mpl::size<list1>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::size<list2>::type::value == 2); + BOOST_STATIC_ASSERT(mpl::front<list1>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::front<list2>::type::value == 1); +} + +int main() +{ + return 0; +} diff --git a/test/logical.cpp b/test/logical.cpp new file mode 100644 index 0000000..43fab1f --- /dev/null +++ b/test/logical.cpp @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/logical.cpp source file +// See http://www.boost.org for updates,documentation,and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use,copy,modify,distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/logical.hpp" +#include "boost/mpl/bool_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +struct my; +struct true_c : mpl::true_c {}; +struct false_c : mpl::false_c {}; + +int main() +{ + BOOST_STATIC_ASSERT((mpl::logical_and< true_c,true_c >::value == true)); + BOOST_STATIC_ASSERT((mpl::logical_and< false_c,true_c >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_and< true_c,false_c >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_and< false_c,false_c >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_and< false_c,my >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_and< false_c,my,my >::value == false)); + + BOOST_STATIC_ASSERT((mpl::logical_or< true_c,true_c >::value == true)); + BOOST_STATIC_ASSERT((mpl::logical_or< false_c,true_c >::value == true)); + BOOST_STATIC_ASSERT((mpl::logical_or< true_c,false_c >::value == true)); + BOOST_STATIC_ASSERT((mpl::logical_or< false_c,false_c >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_or< true_c,my >::value == true)); + BOOST_STATIC_ASSERT((mpl::logical_or< true_c,my,my >::value == true)); + + BOOST_STATIC_ASSERT((mpl::logical_not< true_c >::value == false)); + BOOST_STATIC_ASSERT((mpl::logical_not< false_c >::value == true)); + + return 0; +} diff --git a/test/lower_bound.cpp b/test/lower_bound.cpp new file mode 100644 index 0000000..de11944 --- /dev/null +++ b/test/lower_bound.cpp @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/lower_bound.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/lower_bound.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/comparison/less.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::list_c<int,1,2,3,3,3,5,8> numbers; + typedef mpl::lower_bound< numbers, mpl::int_c<3>, mpl::less<_,_> >::type iter; + BOOST_STATIC_ASSERT((mpl::distance< mpl::begin<numbers>::type,iter >::type::value == 2)); + return 0; +} diff --git a/test/meta_fun.cpp b/test/meta_fun.cpp new file mode 100644 index 0000000..79a7f28 --- /dev/null +++ b/test/meta_fun.cpp @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/meta_fun.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/meta_fun.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +template<typename> struct f1; +template<typename T1, typename T2, typename T3, typename T4, typename T5> struct f5; + +int main() +{ + typedef mpl::meta_fun1<f1> fc1; + typedef mpl::meta_fun5<f5> fc5; + + return 0; +} diff --git a/test/next.cpp b/test/next.cpp new file mode 100644 index 0000000..586d9cb --- /dev/null +++ b/test/next.cpp @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/next.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/next.hpp" +#include "boost/mpl/prior.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/assert_is_same.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::int_c<0> _0; + typedef mpl::int_c<1> _1; + typedef mpl::int_c<2> _2; + + BOOST_MPL_ASSERT_IS_SAME(mpl::next<_0>::type, _1); + BOOST_MPL_ASSERT_IS_SAME(mpl::next<_1>::type, _2); + BOOST_MPL_ASSERT_IS_SAME(mpl::prior<_1>::type, _0); + BOOST_MPL_ASSERT_IS_SAME(mpl::prior<_2>::type, _1); + + return 0; +} diff --git a/test/pop_front.cpp b/test/pop_front.cpp new file mode 100644 index 0000000..7801e34 --- /dev/null +++ b/test/pop_front.cpp @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/pop_front.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/pop_front.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/front.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<long>::type types1; + typedef mpl::list<int,long>::type types2; + typedef mpl::list<char,int,long>::type types3; + + typedef mpl::pop_front<types1>::type result1; + typedef mpl::pop_front<types2>::type result2; + typedef mpl::pop_front<types3>::type result3; + + BOOST_STATIC_ASSERT(mpl::size<result1>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::size<result2>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::size<result3>::type::value == 2); + + BOOST_MPL_ASSERT_IS_SAME(mpl::front<result2>::type, long); + BOOST_MPL_ASSERT_IS_SAME(mpl::front<result3>::type, int); + + return 0; +} diff --git a/test/push_front.cpp b/test/push_front.cpp new file mode 100644 index 0000000..6f573ee --- /dev/null +++ b/test/push_front.cpp @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/push_front.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/push_front.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/front.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<>::type types1; + typedef mpl::list<long>::type types2; + typedef mpl::list<int,long>::type types3; + + typedef mpl::push_front<types1,long>::type result1; + typedef mpl::push_front<types2,int>::type result2; + typedef mpl::push_front<types3,char>::type result3; + + BOOST_STATIC_ASSERT(mpl::size<result1>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::size<result2>::type::value == 2); + BOOST_STATIC_ASSERT(mpl::size<result3>::type::value == 3); + + BOOST_MPL_ASSERT_IS_SAME(mpl::front<result1>::type, long); + BOOST_MPL_ASSERT_IS_SAME(mpl::front<result2>::type, int); + BOOST_MPL_ASSERT_IS_SAME(mpl::front<result3>::type, char); + + return 0; +} diff --git a/test/range_c.cpp b/test/range_c.cpp new file mode 100644 index 0000000..7644f7d --- /dev/null +++ b/test/range_c.cpp @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/range_c.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/empty.hpp" +#include "boost/mpl/size.hpp" +#include "boost/mpl/front.hpp" +#include "boost/mpl/back.hpp" +#include "boost/mpl/assert_is_same.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::range_c<int,0,0> range0; + typedef mpl::range_c<int,0,1> range1; + typedef mpl::range_c<int,0,10> range10; + + BOOST_STATIC_ASSERT(mpl::size<range0>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::size<range1>::type::value == 1); + BOOST_STATIC_ASSERT(mpl::size<range10>::type::value == 10); + + BOOST_STATIC_ASSERT(mpl::empty<range0>::type::value); + BOOST_STATIC_ASSERT(!mpl::empty<range1>::type::value); + BOOST_STATIC_ASSERT(!mpl::empty<range10>::type::value); + + BOOST_MPL_ASSERT_IS_SAME(mpl::begin<range0>::type, mpl::end<range0>::type); + BOOST_MPL_ASSERT_NOT_SAME(mpl::begin<range1>::type, mpl::end<range1>::type); + BOOST_MPL_ASSERT_NOT_SAME(mpl::begin<range10>::type, mpl::end<range10>::type); + + BOOST_STATIC_ASSERT(mpl::front<range1>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::back<range1>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::front<range10>::type::value == 0); + BOOST_STATIC_ASSERT(mpl::back<range10>::type::value == 9); + + return 0; +} diff --git a/test/replace.cpp b/test/replace.cpp new file mode 100644 index 0000000..a4585ff --- /dev/null +++ b/test/replace.cpp @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/replace.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy and John R. Bandela +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/replace.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<int,float,char,float,float,double>::type types; + typedef mpl::replace< types,float,double >::type result; + + typedef mpl::list<int,double,char,double,double,double>::type answer; + BOOST_STATIC_ASSERT((mpl::equal< result,answer >::type::value)); + + return 0; +} diff --git a/test/replace_if.cpp b/test/replace_if.cpp new file mode 100644 index 0000000..936dce0 --- /dev/null +++ b/test/replace_if.cpp @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/replace_if.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy and John R. Bandela +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/replace_if.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/mpl/comparison/greater.hpp" +#include "boost/mpl/comparison/equal_to.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list_c<int,1,4,5,2,7,5,3,5>::type numbers; + typedef mpl::replace_if< numbers, mpl::gt<4>, mpl::int_c<0> >::type result; + + typedef mpl::list_c<int,1,4,0,2,0,0,3,0>::type answer; + BOOST_STATIC_ASSERT((mpl::equal< answer,result,mpl::equal_to<_,_> >::type::value)); + + return 0; +} diff --git a/test/reverse.cpp b/test/reverse.cpp new file mode 100644 index 0000000..47986e3 --- /dev/null +++ b/test/reverse.cpp @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/reverse.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/reverse.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/range_c.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/mpl/comparison/equal_to.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list_c<int,9,8,7,6,5,4,3,2,1,0>::type numbers; + typedef mpl::reverse< numbers >::type result; + + typedef mpl::range_c<int,0,10> answer; + BOOST_STATIC_ASSERT((mpl::equal< result,answer,mpl::equal_to<_,_> >::type::value)); + + return 0; +} diff --git a/test/size.cpp b/test/size.cpp new file mode 100644 index 0000000..2220a5d --- /dev/null +++ b/test/size.cpp @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/size.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/size.hpp" +#include "boost/mpl/list.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + typedef mpl::list<> empty_list; + typedef mpl::list<char,short,int,long> list; + + BOOST_STATIC_ASSERT((mpl::size<empty_list>::type::value == 0)); + BOOST_STATIC_ASSERT((mpl::size<list>::type::value == 4)); + + return 0; +} diff --git a/test/size_of.cpp b/test/size_of.cpp new file mode 100644 index 0000000..b013944 --- /dev/null +++ b/test/size_of.cpp @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/size_of.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/size_of.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +struct my +{ + char a[100]; +}; + +int main() +{ + BOOST_STATIC_ASSERT(mpl::size_of<char>::type::value == sizeof(char)); + BOOST_STATIC_ASSERT(mpl::size_of<int>::type::value == sizeof(int)); + BOOST_STATIC_ASSERT(mpl::size_of<double>::type::value == sizeof(double)); + BOOST_STATIC_ASSERT(mpl::size_of<my>::type::value == sizeof(my)); + return 0; +} diff --git a/test/transform.cpp b/test/transform.cpp new file mode 100644 index 0000000..7fb86e4 --- /dev/null +++ b/test/transform.cpp @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/transform.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/transform.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/type_traits/add_pointer.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list<char,short,int,long,float,double> types; + typedef mpl::list<char*,short*,int*,long*,float*,double*> pointers; + + typedef mpl::transform< types,boost::add_pointer<_1> >::type result; + BOOST_STATIC_ASSERT((mpl::equal<result,pointers>::type::value)); + + return 0; +} diff --git a/test/transform_view.cpp b/test/transform_view.cpp new file mode 100644 index 0000000..667448f --- /dev/null +++ b/test/transform_view.cpp @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/transform_view.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/transform_view.hpp" +#include "boost/mpl/max_element.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/size_of.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +int main() +{ + typedef mpl::list<int,long,char,char[50],double> types; + typedef mpl::max_element< + mpl::transform_view< types, mpl::size_of<_> > + >::type iter; + + BOOST_STATIC_ASSERT(iter::type::value == 50); + return 0; +} diff --git a/test/unique.cpp b/test/unique.cpp new file mode 100644 index 0000000..c50ba70 --- /dev/null +++ b/test/unique.cpp @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/unique.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2000-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/unique.hpp" +#include "boost/mpl/list.hpp" +#include "boost/mpl/equal.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; + +int main() +{ + using namespace mpl::placeholder; + typedef mpl::list<int,float,float,char,int,int,int,double>::type types; + typedef mpl::unique<types>::type result; + + typedef mpl::list<int,float,char,int,double>::type answer; + BOOST_STATIC_ASSERT((mpl::equal< result,answer >::type::value)); + + return 0; +} diff --git a/test/upper_bound.cpp b/test/upper_bound.cpp new file mode 100644 index 0000000..bd37e6d --- /dev/null +++ b/test/upper_bound.cpp @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// boost mpl/test/upper_bound.cpp source file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2001-02 +// Aleksey Gurtovoy +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#include "boost/mpl/upper_bound.hpp" +#include "boost/mpl/list_c.hpp" +#include "boost/mpl/comparison/less.hpp" +#include "boost/mpl/int_c.hpp" +#include "boost/mpl/distance.hpp" +#include "boost/static_assert.hpp" + +namespace mpl = boost::mpl; +using mpl::_; + +#define N 50 + +int main() +{ + typedef mpl::list_c<int,1,2,3,3,3,5,8> numbers; + typedef mpl::upper_bound< numbers, mpl::int_c<3>, mpl::less<_,_> >::type iter; + BOOST_STATIC_ASSERT((mpl::distance< mpl::begin<numbers>::type,iter >::type::value == 5)); + return 0; +}