Boost C++ Libraries
Boost C++ Libraries
Release 1.32.0
CONTENTS
Chapter 1. Boost.Any..................................................................................................................................................................1 1. Introduction .................................................................................................................................................................1 2. Examples .....................................................................................................................................................................1 3. Reference....................................................................................................................................................................3 3.1. ValueType requirements..................................................................................................................................3 3.2. Header <boost/any.hpp>..................................................................................................................................3 Class bad_any_cast..........................................................................................................................................3 Class any..........................................................................................................................................................3 Function any_cast .............................................................................................................................................5 4. Acknowledgements .....................................................................................................................................................6 Chapter 2. Boost.Array..............................................................................................................................................................7 1. Introduction .................................................................................................................................................................7 2. Reference....................................................................................................................................................................7 2.1. Header <boost/array.hpp>................................................................................................................................7 Class template array.........................................................................................................................................8 3. Design Rationale .......................................................................................................................................................12 4. For more information... .............................................................................................................................................13 5. Acknowledgements ...................................................................................................................................................13 Chapter 3. Boost.Function ........................................................................................................................................................14 1. Introduction ...............................................................................................................................................................14 2. History & Compatibility Notes .................................................................................................................................14 3. Tutorial.....................................................................................................................................................................15 3.1. Basic Usage....................................................................................................................................................15 3.2. Free functions.................................................................................................................................................16 3.3. Member functions ...........................................................................................................................................16 3.4. References to Function Objects......................................................................................................................17 3.5. Comparing Boost.Function function objects..................................................................................................17 4. Reference..................................................................................................................................................................18 4.1. Definitions......................................................................................................................................................18 4.2. Header <boost/function.hpp>.........................................................................................................................18 Class bad_function_call.................................................................................................................................19 Class function_base........................................................................................................................................20 Class template functionN...............................................................................................................................21 Class template function..................................................................................................................................25 4.3. Header <boost/function_equal.hpp>..............................................................................................................30 Function template function_equal..................................................................................................................30 5. Frequently Asked Questions.....................................................................................................................................30 6. Miscellaneous Notes.................................................................................................................................................32 6.1. Boost.Function vs. Function Pointers .............................................................................................................32 6.2. Performance ....................................................................................................................................................32 6.2.1. Function object wrapper size ................................................................................................................32 6.2.2. Copying efficiency...............................................................................................................................32 6.2.3. Invocation efficiency............................................................................................................................32 6.3. Combatting virtual function "bloat"...............................................................................................................33 6.4. Acknowledgements........................................................................................................................................33 7. Testsuite....................................................................................................................................................................33 7.1. Acceptance tests.............................................................................................................................................33
i
Chapter 3. Boost.Function 7.2. Negative tests ..................................................................................................................................................34 Chapter 4. Boost.Lambda........................................................................................................................................................35 1. In a nutshell ...............................................................................................................................................................35 2. Getting Started..........................................................................................................................................................35 2.1. Installing the library.......................................................................................................................................35 2.2. Conventions used in this document................................................................................................................36 3. Introduction ...............................................................................................................................................................36 3.1. Motivation......................................................................................................................................................36 3.2. Introduction to lambda expressions................................................................................................................37 3.2.1. Partial function application..................................................................................................................38 3.2.2. Terminology.........................................................................................................................................38 4. Using the library.......................................................................................................................................................38 4.1. Introductory Examples...................................................................................................................................38 4.2. Parameter and return types of lambda functors..............................................................................................39 4.3. About actual arguments to lambda functors...................................................................................................40 4.4. Storing bound arguments in lambda functions...............................................................................................40 5. Lambda expressions in details..................................................................................................................................41 5.1. Placeholders ....................................................................................................................................................41 5.2. Operator expressions......................................................................................................................................41 5.2.1. Operators that cannot be overloaded....................................................................................................42 5.2.2. Assignment and subscript operators .....................................................................................................42 5.2.3. Logical operators..................................................................................................................................42 5.2.4. Comma operator...................................................................................................................................42 5.2.5. Function call operator ...........................................................................................................................42 5.2.6. Member pointer operator ......................................................................................................................42 5.3. Bind expressions .............................................................................................................................................43 5.3.1. Function pointers or references as targets............................................................................................43 5.3.2. Member functions as targets................................................................................................................44 5.3.3. Member variables as targets.................................................................................................................45 5.3.4. Function objects as targets...................................................................................................................45 5.4. Overriding the deduced return type................................................................................................................46 5.4.1. Nullary lambda functors and ret...........................................................................................................47 5.5. Delaying constants and variables...................................................................................................................47 Naming delayed constants and variables.......................................................................................................48 About assignment and subscript operators.....................................................................................................48 5.6. Lambda expressions for control structures.....................................................................................................49 5.6.1. Switch statement..................................................................................................................................50 5.7. Exceptions......................................................................................................................................................50 5.8. Construction and destruction..........................................................................................................................51 5.9. Special lambda expressions............................................................................................................................52 5.9.1. Preventing argument substitution.........................................................................................................52 5.9.2. Rvalues as actual arguments to lambda functors.................................................................................54 5.10. Casts, sizeof and typeid................................................................................................................................54 5.10.1. Cast expressions................................................................................................................................55 5.10.2. Sizeof and typeid................................................................................................................................55 5.11. Nesting STL algorithm invocations ..............................................................................................................55 6. Extending return type deduction system ...................................................................................................................56 7. Practical considerations............................................................................................................................................59 7.1. Performance ....................................................................................................................................................59 7.2. About compiling.............................................................................................................................................60 7.3. Portability.......................................................................................................................................................60 7.3.1. Test coverage ........................................................................................................................................60 8. Relation to other Boost libraries...............................................................................................................................61 8.1. Boost Function ................................................................................................................................................61
ii
Chapter 4. Boost.Lambda 8.2. Boost Bind......................................................................................................................................................62 8.2.1. First argument of bind expression........................................................................................................62 9. Contributors..............................................................................................................................................................63 Appendix A. Rationale for some of the design decisions .............................................................................................63 1. Lambda functor arity........................................................................................................................................63 Bibliography.................................................................................................................................................................63 Chapter 5. Boost.Program_options.........................................................................................................................................65 1. Introduction ...............................................................................................................................................................65 2. Tutorial.....................................................................................................................................................................65 2.1. Getting Started................................................................................................................................................65 2.2. Option Details .................................................................................................................................................66 2.3. Multiple Sources .............................................................................................................................................68 3. Library Overview ......................................................................................................................................................69 3.1. Options Description Component....................................................................................................................70 3.1.1. Syntactic information...........................................................................................................................70 3.1.2. Semantic information...........................................................................................................................71 3.1.3. Positional options.................................................................................................................................71 3.2. Parsers Component.........................................................................................................................................72 3.3. Storage Component........................................................................................................................................72 Warning.................................................................................................................................................................72 3.4. Annotated List of Symbols.............................................................................................................................73 4. How To.....................................................................................................................................................................73 4.1. Nonconventional Syntax..............................................................................................................................73 4.2. Response Files................................................................................................................................................74 4.3. Winmain Command Line...............................................................................................................................74 4.4. Option Groups and Hidden Options...............................................................................................................75 4.5. Custom Validators..........................................................................................................................................76 4.6. Unicode Support.............................................................................................................................................77 5. Design Discussion....................................................................................................................................................77 5.1. Unicode Support.............................................................................................................................................77 6. Acknowledgements ...................................................................................................................................................79 7. Reference..................................................................................................................................................................80 7.1. Header <boost/program_options/cmdline.hpp>.............................................................................................80 Type style_t....................................................................................................................................................80 7.2. Header <boost/program_options/environment_iterator.hpp>........................................................................80 Class environment_iterator............................................................................................................................80 7.3. Header <boost/program_options/eof_iterator.hpp>.......................................................................................81 Class template eof_iterator.............................................................................................................................81 7.4. Header <boost/program_options/errors.hpp>................................................................................................82 Class error......................................................................................................................................................82 Class invalid_syntax .......................................................................................................................................83 Class unknown_option...................................................................................................................................83 Class ambiguous_option................................................................................................................................84 Class multiple_values .....................................................................................................................................84 Class multiple_occurrences............................................................................................................................85 Class validation_error....................................................................................................................................85 Class invalid_option_value............................................................................................................................86 Class too_many_positional_options_error.....................................................................................................87 Class too_few_positional_options_error........................................................................................................87 Class invalid_command_line_syntax.............................................................................................................88 Class invalid_command_line_style................................................................................................................88 7.5. Header <boost/program_options/option.hpp> ................................................................................................89 Class template basic_option...........................................................................................................................89 7.6. Header <boost/program_options/options_description.hpp>..........................................................................89
iii
Chapter 5. Boost.Program_options Class option_description................................................................................................................................90 Class options_description_easy_init..............................................................................................................91 Class options_description ...............................................................................................................................92 Class duplicate_option_error ..........................................................................................................................93 7.7. Header <boost/program_options/parsers.hpp>..............................................................................................94 Class template basic_parsed_options.............................................................................................................94 Class basic_parsed_options<wchar_t>..........................................................................................................95 Class common_command_line_parser ...........................................................................................................96 Class template basic_command_line_parser ..................................................................................................96 Function template parse_command_line ........................................................................................................97 Function template parse_config_file..............................................................................................................98 Function parse_environment..........................................................................................................................98 Function parse_environment..........................................................................................................................98 7.8. Header <boost/program_options/positional_options.hpp>............................................................................99 Class positional_options_description.............................................................................................................99 7.9. Header <boost/program_options/value_semantic.hpp>...............................................................................100 Class value_semantic...................................................................................................................................100 Class template value_semantic_codecvt_helper..........................................................................................101 Class value_semantic_codecvt_helper<char> ..............................................................................................101 Class value_semantic_codecvt_helper<wchar_t> ........................................................................................102 Class untyped_value .....................................................................................................................................103 Class template typed_value..........................................................................................................................103 Function value..............................................................................................................................................105 Function wvalue...........................................................................................................................................105 Function bool_switch...................................................................................................................................105 7.10. Header <boost/program_options/variables_map.hpp>..............................................................................106 Class variable_value .....................................................................................................................................106 Class abstract_variables_map......................................................................................................................107 Class variables_map.....................................................................................................................................108 Function store...............................................................................................................................................109 Function store...............................................................................................................................................109 Function notify.............................................................................................................................................109 7.11. Header <boost/program_options/version.hpp>..........................................................................................110 Macro BOOST_PROGRAM_OPTIONS_VERSION.................................................................................110 Chapter 6. Boost.Ref...............................................................................................................................................................111 1. Introduction .............................................................................................................................................................111 2. Reference................................................................................................................................................................111 2.1. Header <boost/ref.hpp>................................................................................................................................111 Class template reference_wrapper...............................................................................................................112 Class template is_reference_wrapper...........................................................................................................113 Class template unwrap_reference .................................................................................................................113 3. Acknowledgements .................................................................................................................................................114 Chapter 7. Boost.Signals .........................................................................................................................................................115 1. Introduction .............................................................................................................................................................115 2. Tutorial...................................................................................................................................................................115 2.1. How to Read this Tutorial............................................................................................................................115 2.2. Compatibility Note.......................................................................................................................................115 2.3. Hello, World! (Beginner).............................................................................................................................116 2.4. Calling multiple slots ....................................................................................................................................116 2.4.1. Connecting multiple slots (Beginner)................................................................................................116 2.4.2. Ordering slot call groups (Intermediate)............................................................................................117 2.5. Passing values to and from slots ...................................................................................................................118 2.5.1. Slot Arguments (Beginner)................................................................................................................118
iv
Chapter 7. Boost.Signals 2.5.2. Signal Return Values (Advanced)......................................................................................................118 2.6. Connection Management..............................................................................................................................121 2.6.1. Disconnecting Slots (Beginner).........................................................................................................121 2.6.2. Scoped connections (Intermediate)....................................................................................................121 2.6.3. Disconnecting equivalent slots (Intermediate)...................................................................................121 2.6.4. Automatic connection management (Intermediate)...........................................................................122 2.6.5. When can disconnections occur? (Intermediate)...............................................................................123 2.6.6. Passing slots (Intermediate)...............................................................................................................123 2.7. Linking against the Signals library...............................................................................................................124 3. Reference................................................................................................................................................................124 3.1. Header <boost/signal.hpp>...........................................................................................................................124 Class template signalN.................................................................................................................................124 Class template signal....................................................................................................................................128 3.2. Header <boost/signals/slot.hpp>..................................................................................................................128 Class template slot ........................................................................................................................................128 3.3. Header <boost/signals/trackable.hpp>.........................................................................................................129 Class trackable ..............................................................................................................................................129 3.4. Header <boost/signals/connection.hpp>......................................................................................................130 Class connection ...........................................................................................................................................130 Class scoped_connection ..............................................................................................................................132 3.5. Header <boost/visit_each.hpp>....................................................................................................................133 Function template visit_each ........................................................................................................................133 3.6. Header <boost/last_value.hpp>....................................................................................................................134 Class template last_value.............................................................................................................................134 Class last_value<void>................................................................................................................................134 4. Frequently Asked Questions...................................................................................................................................135 5. Design Overview....................................................................................................................................................135 5.1. Type Erasure .................................................................................................................................................135 5.2. connection class............................................................................................................................................136 5.3. Slot Call Iterator...........................................................................................................................................136 5.4. visit_each function template.........................................................................................................................136 6. Design Rationale .....................................................................................................................................................137 6.1. Choice of Slot Definitions............................................................................................................................137 6.2. Userlevel Connection Management...........................................................................................................137 6.3. Combiner Interface.......................................................................................................................................138 6.4. Connection Interfaces: += operator..............................................................................................................139 6.5. trackable rationale........................................................................................................................................139 6.5.1. trackable copying behavior................................................................................................................139 6.5.2. Why derivation from trackable? .........................................................................................................140 6.6. Comparison with other Signal/Slot implementations...................................................................................140 6.6.1. libsigc++.............................................................................................................................................140 6.6.2. .NET delegates...................................................................................................................................140 7. Testsuite..................................................................................................................................................................140 7.1. Acceptance tests...........................................................................................................................................140 Chapter 8. Boost String Algorithms Library.......................................................................................................................142 1. Introduction .............................................................................................................................................................142 2. Usage......................................................................................................................................................................142 2.1. First Example ................................................................................................................................................142 2.2. Case conversion............................................................................................................................................143 2.3. Predicates and Classification........................................................................................................................143 2.4. Trimming......................................................................................................................................................144 2.5. Find algorithms .............................................................................................................................................144 2.6. Replace Algorithms......................................................................................................................................145 2.7. Find Iterator..................................................................................................................................................145
v
Chapter 8. Boost String Algorithms Library 2.8. Split ...............................................................................................................................................................146 3. Quick Reference.....................................................................................................................................................146 3.1. Algorithms....................................................................................................................................................146 3.2. Finders and Formatters.................................................................................................................................149 3.3. Iterators.........................................................................................................................................................150 3.4. Classification................................................................................................................................................150 4. Design Topics.........................................................................................................................................................150 4.1. String Representation...................................................................................................................................150 4.2. iterator_range class.......................................................................................................................................151 4.3. Collection Traits...........................................................................................................................................151 4.4. Sequence Traits............................................................................................................................................152 4.5. Find Algorithms ............................................................................................................................................153 4.6. Replace Algorithms......................................................................................................................................153 4.7. Find Iterators & Split Algorithms .................................................................................................................153 4.8. Exception Safety ...........................................................................................................................................153 5. Concepts.................................................................................................................................................................154 5.1. Definitions....................................................................................................................................................154 5.2. Finder Concept.............................................................................................................................................154 5.3. Formatter concept.........................................................................................................................................155 6. Reference................................................................................................................................................................156 6.1. Header <boost/algorithm/string/case_conv.hpp>.........................................................................................156 Function to_lower_copy ...............................................................................................................................156 Function template to_lower ..........................................................................................................................157 Function to_upper_copy ...............................................................................................................................157 Function template to_upper ..........................................................................................................................158 6.2. Header <boost/algorithm/string/classification.hpp>....................................................................................158 Function is_classified...................................................................................................................................159 Function is_space.........................................................................................................................................159 Function is_alnum........................................................................................................................................159 Function is_alpha.........................................................................................................................................160 Function is_cntrl ...........................................................................................................................................160 Function is_digit ...........................................................................................................................................161 Function is_graph.........................................................................................................................................161 Function is_lower.........................................................................................................................................161 Function is_print..........................................................................................................................................162 Function is_punct.........................................................................................................................................162 Function is_upper.........................................................................................................................................162 Function is_xdigit .........................................................................................................................................163 Function template is_any_of........................................................................................................................163 Function template is_from_range .................................................................................................................164 Function template operator&&....................................................................................................................164 Function template operator||.........................................................................................................................165 Function template operator!.........................................................................................................................165 6.3. Header <boost/algorithm/string/collection_traits.hpp> ................................................................................165 Struct template collection_traits...................................................................................................................166 Struct template value_type_of ......................................................................................................................167 Struct template difference_type_of..............................................................................................................167 Struct template iterator_of ............................................................................................................................167 Struct template const_iterator_of.................................................................................................................167 Struct template result_iterator_of.................................................................................................................168 Function template size ..................................................................................................................................168 Function template empty..............................................................................................................................168 Function begin..............................................................................................................................................169 Function end.................................................................................................................................................169 6.4. Header <boost/algorithm/string/compare.hpp> ............................................................................................169
vi
Chapter 8. Boost String Algorithms Library Struct is_equal..............................................................................................................................................169 Struct is_iequal.............................................................................................................................................170 6.5. Header <boost/algorithm/string/concept.hpp>.............................................................................................170 Struct template FinderConcept.....................................................................................................................171 Struct template FormatterConcept...............................................................................................................171 6.6. Header <boost/algorithm/string/constants.hpp>..........................................................................................171 Type token_compress_mode_type...............................................................................................................172 6.7. Header <boost/algorithm/string/erase.hpp>.................................................................................................172 Function erase_range_copy..........................................................................................................................173 Function template erase_range.....................................................................................................................174 Function erase_first_copy............................................................................................................................174 Function template erase_first.......................................................................................................................175 Function ierase_first_copy...........................................................................................................................175 Function template ierase_first......................................................................................................................176 Function erase_last_copy.............................................................................................................................177 Function template erase_last........................................................................................................................177 Function ierase_last_copy............................................................................................................................178 Function template ierase_last.......................................................................................................................178 Function erase_nth_copy ..............................................................................................................................179 Function template erase_nth .........................................................................................................................179 Function ierase_nth_copy............................................................................................................................180 Function template ierase_nth.......................................................................................................................181 Function erase_all_copy ...............................................................................................................................181 Function template erase_all ..........................................................................................................................182 Function ierase_all_copy ..............................................................................................................................182 Function template ierase_all .........................................................................................................................183 Function erase_head_copy...........................................................................................................................183 Function template erase_head......................................................................................................................184 Function erase_tail_copy ..............................................................................................................................184 Function template erase_tail .........................................................................................................................185 6.8. Header <boost/algorithm/string/find.hpp>...................................................................................................185 Function template find.................................................................................................................................186 Function template find_first.........................................................................................................................186 Function template ifind_first........................................................................................................................187 Function template find_last..........................................................................................................................187 Function template ifind_last.........................................................................................................................188 Function template find_nth..........................................................................................................................188 Function template ifind_nth.........................................................................................................................189 Function template find_head........................................................................................................................189 Function template find_tail..........................................................................................................................190 Function template find_token .......................................................................................................................191 6.9. Header <boost/algorithm/string/find_format.hpp>......................................................................................191 Function find_format_copy..........................................................................................................................192 Function template find_format.....................................................................................................................192 Function find_format_all_copy....................................................................................................................193 Function template find_format_all...............................................................................................................193 Function template regex_finder...................................................................................................................194 Function template regex_formatter..............................................................................................................194 6.10. Header <boost/algorithm/string/find_iterator.hpp>...................................................................................195 Class template find_iterator.........................................................................................................................195 Class template split_iterator.........................................................................................................................196 Function template make_find_iterator.........................................................................................................197 Function template make_split_iterator.........................................................................................................198 6.11. Header <boost/algorithm/string/finder.hpp>..............................................................................................198 Function first_finder .....................................................................................................................................198
vii
Chapter 8. Boost String Algorithms Library Function last_finder ......................................................................................................................................199 Function nth_finder......................................................................................................................................199 Function head_finder ....................................................................................................................................200 Function tail_finder......................................................................................................................................200 Function template token_finder...................................................................................................................201 Function range_finder..................................................................................................................................201 6.12. Header <boost/algorithm/string/formatter.hpp>........................................................................................202 Function template const_formatter ...............................................................................................................202 Function template identity_formatter...........................................................................................................202 Function template empty_formatter.............................................................................................................203 6.13. Header <boost/algorithm/string/iterator_range.hpp>.................................................................................203 Class template iterator_range.......................................................................................................................203 Function template operator<<......................................................................................................................205 Function template make_iterator_range.......................................................................................................205 Function template make_iterator_range.......................................................................................................206 Function template copy_iterator_range ........................................................................................................206 Function template transform_iterator_range................................................................................................206 6.14. Header <boost/algorithm/string/predicate.hpp>.........................................................................................207 Function starts_with.....................................................................................................................................208 Function template istarts_with.....................................................................................................................208 Function ends_with......................................................................................................................................209 Function template iends_with......................................................................................................................209 Function contains.........................................................................................................................................210 Function template icontains.........................................................................................................................210 Function equals............................................................................................................................................211 Function template iequals .............................................................................................................................211 Function template all....................................................................................................................................212 6.15. Header <boost/algorithm/string/regex.hpp>..............................................................................................212 Function template find_regex .......................................................................................................................214 Function replace_regex_copy......................................................................................................................215 Function template replace_regex.................................................................................................................215 Function replace_all_regex_copy................................................................................................................216 Function template replace_all_regex...........................................................................................................217 Function erase_regex_copy..........................................................................................................................217 Function template erase_regex.....................................................................................................................218 Function erase_all_regex_copy....................................................................................................................218 Function template erase_all_regex...............................................................................................................219 Function template find_all_regex .................................................................................................................219 Function template split_regex......................................................................................................................220 6.16. Header <boost/algorithm/string/regex_find_format.hpp>.........................................................................221 Function template regex_finder...................................................................................................................221 Function template regex_formatter..............................................................................................................222 6.17. Header <boost/algorithm/string/replace.hpp>............................................................................................222 Function replace_range_copy......................................................................................................................224 Function template replace_range.................................................................................................................225 Function replace_first_copy.........................................................................................................................225 Function template replace_first....................................................................................................................226 Function ireplace_first_copy........................................................................................................................226 Function template ireplace_first...................................................................................................................227 Function replace_last_copy..........................................................................................................................228 Function template replace_last.....................................................................................................................228 Function ireplace_last_copy .........................................................................................................................229 Function template ireplace_last ....................................................................................................................229 Function replace_nth_copy..........................................................................................................................230 Function template replace_nth.....................................................................................................................231
viii
Chapter 8. Boost String Algorithms Library Function ireplace_nth_copy.........................................................................................................................231 Function template ireplace_nth....................................................................................................................232 Function replace_all_copy...........................................................................................................................232 Function template replace_all......................................................................................................................233 Function ireplace_all_copy..........................................................................................................................234 Function template ireplace_all.....................................................................................................................234 Function replace_head_copy........................................................................................................................235 Function template replace_head...................................................................................................................235 Function replace_tail_copy..........................................................................................................................236 Function template replace_tail.....................................................................................................................237 6.18. Header <boost/algorithm/string/sequence_traits.hpp>...............................................................................237 Class template has_native_replace...............................................................................................................237 Class template has_stable_iterators ..............................................................................................................238 Class template has_const_time_insert ..........................................................................................................238 Class template has_const_time_erase..........................................................................................................239 6.19. Header <boost/algorithm/string/split.hpp>................................................................................................239 Function template find_all...........................................................................................................................240 Function template ifind_all..........................................................................................................................240 Function template split.................................................................................................................................241 6.20. Header <boost/algorithm/string/std_containers_traits.hpp>......................................................................242 6.21. Header <boost/algorithm/string.hpp>........................................................................................................242 6.22. Header <boost/algorithm/string_regex.hpp> ..............................................................................................242 6.23. Header <boost/algorithm/string/trim.hpp>.................................................................................................242 Function trim_left_copy_if..........................................................................................................................243 Function template trim_left_copy................................................................................................................243 Function template trim_left_if.....................................................................................................................244 Function template trim_left..........................................................................................................................244 Function trim_right_copy_if........................................................................................................................245 Function template trim_right_copy..............................................................................................................245 Function template trim_right_if...................................................................................................................246 Function template trim_right ........................................................................................................................246 Function trim_copy_if..................................................................................................................................246 Function template trim_copy.......................................................................................................................247 Function template trim_if.............................................................................................................................248 Function template trim.................................................................................................................................248 7. Rationale.................................................................................................................................................................248 7.1. Locales ..........................................................................................................................................................248 7.2. Regular Expressions.....................................................................................................................................249 8. Environment...........................................................................................................................................................249 8.1. Build.............................................................................................................................................................249 8.2. Examples......................................................................................................................................................249 8.3. Tests ..............................................................................................................................................................249 8.4. Portability.....................................................................................................................................................249 9. Credits.....................................................................................................................................................................249 9.1. Acknowledgments........................................................................................................................................249 Chapter 9. Boost.Threads.......................................................................................................................................................251 1. Overview .................................................................................................................................................................251 1.1. Introduction..................................................................................................................................................251 1.2. Dangers.........................................................................................................................................................251 1.2.1. General considerations.......................................................................................................................251 Note.....................................................................................................................................................................251 1.2.2. Testing and debugging considerations...............................................................................................252 1.2.3. Getting a head start .............................................................................................................................252 1.3. C++ Standard Library usage in multithreaded programs.............................................................................252
ix
Chapter 9. Boost.Threads 1.3.1. Runtime libraries................................................................................................................................252 1.3.2. Potentially nonthreadsafe functions...............................................................................................252 1.4. Common guarantees for all Boost.Threads components..............................................................................253 1.4.1. Exceptions..........................................................................................................................................253 1.4.2. NonCopyable requirement.................................................................................................................253 2. Design.....................................................................................................................................................................253 2.1. Goals.............................................................................................................................................................253 2.2. Iterative Phases.............................................................................................................................................254 2.3. Phase 1, Synchronization Primitives............................................................................................................254 2.4. Phase 2, Thread Management and Thread Specific Storage........................................................................254 2.5. The Next Phase.............................................................................................................................................254 3. Concepts.................................................................................................................................................................254 3.1. Mutexes........................................................................................................................................................255 Note.....................................................................................................................................................................255 3.1.1. Locking Strategies..............................................................................................................................255 3.1.2. Scheduling Policies............................................................................................................................256 3.1.3. Mutex Concepts ..................................................................................................................................256 3.1.4. Mutex Models....................................................................................................................................257 3.1.5. Lock Concepts....................................................................................................................................258 3.1.6. Lock Models .......................................................................................................................................260 3.2. Read/Write Mutexes.....................................................................................................................................261 Note.....................................................................................................................................................................261 3.2.1. Locking Strategies..............................................................................................................................261 3.2.2. Scheduling Policies............................................................................................................................263 3.2.3. Mutex Concepts ..................................................................................................................................267 3.2.4. Mutex Models....................................................................................................................................268 3.2.5. Lock Concepts....................................................................................................................................268 3.2.6. Lock Models .......................................................................................................................................272 4. Rationale.................................................................................................................................................................273 4.1. Rationale for the Creation of Boost.Threads................................................................................................273 4.2. Rationale for the Low Level Primitives Supported in Boost.Threads ..........................................................273 4.3. Rationale for the Lock Design ......................................................................................................................273 4.4. Rationale for NonCopyable Thread Type....................................................................................................274 4.4.1. 1. Use case: Simple creation of a thread............................................................................................274 4.4.2. 2. Use case: Creation of a thread that's later joined...........................................................................275 4.4.3. 3. Use case: Simple creation of several threads in a loop..................................................................275 4.4.4. 4. Use case: Creation of several threads in a loop which are later joined..........................................275 4.4.5. 5. Use case: Creation of a thread whose ownership is passed to another object/method. ..................275 4.4.6. 6. Use case: Creation of a thread whose ownership is shared between multiple objects...................275 4.4.7. 1. Comparison: simple creation of a thread. .......................................................................................276 4.4.8. 2. Comparison: creation of a thread that's later joined.......................................................................276 4.4.9. 3. Comparison: simple creation of several threads in a loop.............................................................276 4.4.10. 4. Comparison: creation of several threads in a loop which are later joined...................................276 4.4.11. 5. Comparison: creation of a thread whose ownership is passed to another object/method............277 4.4.12. 6. Comparison: creation of a thread whose ownership is shared between multiple objects............277 4.5. Rationale for not providing Event Variables................................................................................................278 5. Reference................................................................................................................................................................278 5.1. Header <boost/thread/barrier.hpp>..............................................................................................................278 Class barrier ..................................................................................................................................................278 5.2. Header <boost/thread/condition.hpp>..........................................................................................................279 Class condition.............................................................................................................................................279 5.3. Header <boost/thread/exceptions.hpp>........................................................................................................282 Class lock_error ............................................................................................................................................282 Class thread_resource_error.........................................................................................................................282 5.4. Header <boost/thread/mutex.hpp>...............................................................................................................283
x
Chapter 9. Boost.Threads Class mutex..................................................................................................................................................283 Class try_mutex............................................................................................................................................284 Class timed_mutex.......................................................................................................................................285 5.5. Header <boost/thread/once.hpp> ..................................................................................................................286 Macro BOOST_ONCE_INIT......................................................................................................................286 Function call_once.......................................................................................................................................287 5.6. Header <boost/thread/recursive_mutex.hpp>..............................................................................................287 Class recursive_mutex ..................................................................................................................................287 Class recursive_try_mutex...........................................................................................................................289 Class recursive_timed_mutex......................................................................................................................290 5.7. Header <boost/thread/read_write_mutex.hpp>............................................................................................291 Type read_write_scheduling_policy............................................................................................................291 Class read_write_mutex...............................................................................................................................291 Note.....................................................................................................................................................................292 read_write_mutex construct/copy/destruct..................................................................................................292 Class try_read_write_mutex .........................................................................................................................293 Note.....................................................................................................................................................................294 try_read_write_mutex construct/copy/destruct............................................................................................294 Class timed_read_write_mutex....................................................................................................................294 Note.....................................................................................................................................................................295 timed_read_write_mutex construct/copy/destruct.......................................................................................295 5.8. Header <boost/thread/thread.hpp>...............................................................................................................295 Class thread..................................................................................................................................................296 Note.....................................................................................................................................................................296 thread construct/copy/destruct ......................................................................................................................296 Class thread_group.......................................................................................................................................298 5.9. Header <boost/thread/tss.hpp>.....................................................................................................................299 Class thread_specific_ptr.............................................................................................................................299 5.10. Header <boost/thread/xtime.hpp>..............................................................................................................301 Type xtime_clock_types..............................................................................................................................302 Struct xtime..................................................................................................................................................302 6. Frequently Asked Questions...................................................................................................................................302 7. Configuration..........................................................................................................................................................304 7.1. Library Defined Public Macros....................................................................................................................304 7.2. Library Defined Implementation Macros.....................................................................................................305 8. Build.......................................................................................................................................................................305 8.1. Building the Boost.Threads Libraries ...........................................................................................................305 Note.....................................................................................................................................................................305 8.2. Testing the Boost.Threads Libraries .............................................................................................................305 9. Implementation Notes .............................................................................................................................................306 9.1. Win32...........................................................................................................................................................306 10. Release Notes ........................................................................................................................................................306 10.1. Boost 1.32.0................................................................................................................................................306 10.1.1. Documentation converted to BoostBook.........................................................................................306 10.1.2. Staticallylink build option added...................................................................................................306 10.1.3. Barrier functionality added ...............................................................................................................307 10.1.4. Read/write mutex functionality added.............................................................................................307 Note.....................................................................................................................................................................307 10.1.5. Threadspecific pointer functionality changed................................................................................307 10.1.6. Mutex implementation changed for Win32.....................................................................................307 10.1.7. Windows CE support improved.......................................................................................................307 Glossary......................................................................................................................................................................307 11. Acknowledgements ...............................................................................................................................................310 Bibliography...............................................................................................................................................................311
xi
Chapter 10. Boost.Tribool......................................................................................................................................................313 1. Introduction .............................................................................................................................................................313 2. Tutorial...................................................................................................................................................................313 2.1. Basic usage...................................................................................................................................................313 2.2. Renaming the indeterminate state................................................................................................................314 2.3. tribool input/output.......................................................................................................................................314 3. Reference................................................................................................................................................................315 3.1. Header <boost/logic/tribool.hpp>................................................................................................................315 Class tribool ..................................................................................................................................................315 Function indeterminate .................................................................................................................................316 Function operator!........................................................................................................................................317 Function operator&&...................................................................................................................................317 Function operator||........................................................................................................................................317 Function operator==.....................................................................................................................................318 Function operator!=......................................................................................................................................318 Macro BOOST_TRIBOOL_THIRD_STATE.............................................................................................319 3.2. Header <boost/logic/tribool_fwd.hpp>........................................................................................................319 3.3. Header <boost/logic/tribool_io.hpp>...........................................................................................................319 Class template indeterminate_name.............................................................................................................320 Function template get_default_indeterminate_name...................................................................................320 Function template operator<<......................................................................................................................321 Function template operator>>......................................................................................................................321 4. Testsuite..................................................................................................................................................................322 4.1. Acceptance tests...........................................................................................................................................322 Chapter 11. Boost.Variant ......................................................................................................................................................323 1. Introduction .............................................................................................................................................................323 1.1. Abstract .........................................................................................................................................................323 1.2. Motivation....................................................................................................................................................323 1.2.1. Problem..............................................................................................................................................323 1.2.2. Solution: A Motivating Example.......................................................................................................324 2. Tutorial...................................................................................................................................................................324 2.1. Basic Usage..................................................................................................................................................324 2.2. Advanced Topics..........................................................................................................................................326 2.2.1. Preprocessor macros ...........................................................................................................................327 2.2.2. Using a type sequence to specify bounded types...............................................................................327 2.2.3. Recursive variant types......................................................................................................................327 2.2.4. Binary visitation.................................................................................................................................330 3. Reference................................................................................................................................................................331 3.1. Concepts.......................................................................................................................................................331 3.1.1. BoundedType.....................................................................................................................................331 3.1.2. StaticVisitor ........................................................................................................................................331 3.1.3. OutputStreamable...............................................................................................................................332 3.2. Header <boost/variant.hpp>.........................................................................................................................332 3.3. Header <boost/variant/variant_fwd.hpp>.....................................................................................................332 Macro BOOST_VARIANT_LIMIT_TYPES..............................................................................................332 Macro BOOST_VARIANT_ENUM_PARAMS.........................................................................................333 Macro BOOST_VARIANT_ENUM_SHIFTED_PARAMS .......................................................................333 Macro BOOST_VARIANT_NO_REFERENCE_SUPPORT.....................................................................333 Macro BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT...........................................................334 Macro BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT......................................334 3.4. Header <boost/variant/variant.hpp>.............................................................................................................334 Class template variant..................................................................................................................................334 Function template swap ................................................................................................................................338 Function template operator<<......................................................................................................................339 Class template make_variant_over ...............................................................................................................339
xii
Chapter 11. Boost.Variant 3.5. Header <boost/variant/recursive_variant.hpp>............................................................................................340 Class template make_recursive_variant.......................................................................................................340 Class template make_recursive_variant_over..............................................................................................340 3.6. Header <boost/variant/recursive_wrapper.hpp>..........................................................................................341 Class template recursive_wrapper ................................................................................................................341 Class template is_recursive_wrapper...........................................................................................................343 Class template unwrap_recursive_wrapper ..................................................................................................344 3.7. Header <boost/variant/apply_visitor.hpp>...................................................................................................344 Class template apply_visitor_delayed_t.......................................................................................................344 Function apply_visitor ..................................................................................................................................345 3.8. Header <boost/variant/get.hpp>...................................................................................................................346 Class bad_get ................................................................................................................................................346 Function get..................................................................................................................................................346 3.9. Header <boost/variant/bad_visit.hpp>.........................................................................................................347 Class bad_visit ..............................................................................................................................................347 3.10. Header <boost/variant/static_visitor.hpp>.................................................................................................348 Class template static_visitor.........................................................................................................................348 3.11. Header <boost/variant/visitor_ptr.hpp>.....................................................................................................348 Class template visitor_ptr_t ..........................................................................................................................348 Function template visitor_ptr.......................................................................................................................349 4. Design Overview....................................................................................................................................................349 4.1. "NeverEmpty" Guarantee...........................................................................................................................349 4.1.1. The Guarantee....................................................................................................................................349 4.1.2. The Implementation Problem.............................................................................................................350 4.1.3. The "Ideal" Solution: False Hopes.....................................................................................................350 4.1.4. An Initial Solution: Double Storage...................................................................................................351 4.1.5. Current Approach: Temporary Heap Backup....................................................................................351 4.1.6. Enabling Optimizations......................................................................................................................352 4.1.7. Future Direction: Policybased Implementation...............................................................................352 5. Miscellaneous Notes...............................................................................................................................................352 5.1. Boost.Variant vs. Boost.Any........................................................................................................................353 5.2. Portability.....................................................................................................................................................353 5.3. Troubleshooting ............................................................................................................................................354 5.3.1. "Template instantiation depth exceeds maximum"............................................................................354 5.3.2. "Internal heap limit reached" ..............................................................................................................354 5.4. Acknowledgments........................................................................................................................................354 6. References ...............................................................................................................................................................354
xiii
Chapter 1. Boost.Any
Kevlin Henney Copyright 2001 Kevlin Henney
1. Introduction
There are times when a generic (in the sense of general as opposed to templatebased programming) type is needed: variables that are truly variable, accommodating values of many other more specific types rather than C++'s normal strict and static types. We can distinguish three basic kinds of generic type: Converting types that can hold one of a number of possible value types, e.g. int and string, and freely convert between them, for instance interpreting 5 as "5" or viceversa. Such types are common in scripting and other interpreted languages. boost::lexical_cast supports such conversion functionality. Discriminated types that contain values of different types but do not attempt conversion between them, i.e. 5 is held strictly as an int and is not implicitly convertible either to "5" or to 5.0. Their indifference to interpretation but awareness of type effectively makes them safe, generic containers of single values, with no scope for surprises from ambiguous conversions. Indiscriminate types that can refer to anything but are oblivious to the actual underlying type, entrusting all forms of access and interpretation to the programmer. This niche is dominated by void *, which offers plenty of scope for surprising, undefined behavior. The boost::any class (based on the class of the same name described in "Valued Conversions" by Kevlin Henney, C++ Report 12(7), July/August 2000) is a variant value type based on the second category. It supports copying of any value type and safe checked extraction of that value strictly against its type. A similar design, offering more appropriate operators, can be used for a generalized function adaptor, any_function, a generalized iterator adaptor, any_iterator, and other object types that need uniform runtime treatment but support only compiletime template parameter conformance.
2. Examples
The following code demonstrates the syntax for using implicit conversions to and copying of any objects:
#include <list> #include <boost/any.hpp> using boost::any_cast; typedef std::list<boost::any> many; void append_int(many & values, int value) { boost::any to_append = value; values.push_back(to_append); } void append_string(many & values, const std::string & value) { values.push_back(value); } void append_char_ptr(many & values, const char * value) { values.push_back(value); } void append_any(many & values, const boost::any & value) { values.push_back(value); }
Chapter 1. Boost.Any
void append_nothing(many & values) { values.push_back(boost::any()); }
The following predicates follow on from the previous definitions and demonstrate the use of queries on any objects:
bool is_empty(const boost::any & operand) { return operand.empty(); } bool is_int(const boost::any & operand) { return operand.type() == typeid(int); } bool is_char_ptr(const boost::any & operand) { try { any_cast<const char *>(operand); return true; } catch(const boost::bad_any_cast &) { return false; } } bool is_string(const boost::any & operand) { return any_cast<std::string>(&operand); } void count_all(many & values, std::ostream & out) { out << "#empty == " << std::count_if(values.begin(), values.end(), out << "#int == " << std::count_if(values.begin(), values.end(), out << "#const char * == " << std::count_if(values.begin(), values.end(), out << "#string == " << std::count_if(values.begin(), values.end(), }
is_empty) << std::endl; is_int) << std::endl; is_char_ptr) << std::endl; is_string) << std::endl;
The following type, patterned after the OMG's Property Service, defines namevalue pairs for arbitrary value types:
struct property { property(); property(const std::string &, const boost::any &); std::string name; boost::any value; }; typedef std::list<property> properties;
The following base class demonstrates one approach to runtime polymorphism based callbacks that also require arbitrary argument types. The absence of virtual member templates requires that different solutions have different tradeoffs in terms of efficiency, safety, and generality. Using a checked variant type offers one approach:
class consumer {
Chapter 1. Boost.Any
public: virtual void notify(const any &) = 0; ... };
3. Reference
3.1. ValueType requirements
Values are strongly informational objects for which identity is not significant, i.e. the focus is principally on their state content and any behavior organized around that. Another distinguishing feature of values is their granularity: normally finegrained objects representing simple concepts in the system such as quantities. As the emphasis of a value lies in its state not its identity, values can be copied and typically assigned one to another, requiring the explicit or implicit definition of a public copy constructor and public assignment operator. Values typically live within other scopes, i.e. within objects or blocks, rather than on the heap. Values are therefore normally passed around and manipulated directly as variables or through references, but not as pointers that emphasize identity and indirection. The specific requirements on value types to be used in an any are: A ValueType is CopyConstructible [20.1.3]. A ValueType is optionally Assignable [23.1]. The strong exceptionsafety guarantee is required for all forms of assignment. The destructor for a ValueType upholds the nothrow exceptionsafety guarantee.
Class any boost::any A class whose instances can hold instances of any type that satisfies ValueType requirements.
Chapter 1. Boost.Any
Synopsis class any { public: // construct/copy/destruct any(); any(const any &); template<typename ValueType> any(const ValueType &); any & operator=(const any &); template<typename ValueType> any & operator=(const ValueType &); ~any(); // modifiers any & swap(any &); // queries bool empty() const; const std::type_info & type() const; };
Description
any construct/copy/destruct
1. any(); Postconditions this>empty() 2. any(const any & other); Effects Copy constructor that copies content of other into new instance, so that any content is equivalent in both type and value to the content of other, or empty if other is empty. Throws May fail with a std::bad_alloc exception or any exceptions arising from the copy constructor of the contained type. 3. template<typename ValueType> any(const ValueType & value); Effects Makes a copy of value, so that the initial content of the new instance is equivalent in both type and value to value. Throws std::bad_alloc or any exceptions arising from the copy constructor of the contained type. 4. any & operator=(const any & rhs); Effects Copies content of rhs into current instance, discarding previous content, so that the new content is equivalent in both type and value to the content of rhs, or empty if rhs.empty(). Throws std::bad_alloc or any exceptions arising from the copy constructor of the contained type. Assignment satisfies the strong guarantee of exception safety. 5. template<typename ValueType> any & operator=(const ValueType & rhs); Effects Makes a copy of rhs, discarding previous content, so that the new content of is equivalent in both type and value to rhs. Throws std::bad_alloc or any exceptions arising from the copy constructor of the contained type. Assignment satisfies the strong guarantee of exception safety.
4
Chapter 1. Boost.Any
6. ~any(); Effects Releases any and all resources used in management of instance. Throws Nothing.
any modifiers
1. any & swap(any & rhs); Effects Exchange of the contents of *this and rhs. Returns *this Throws Nothing.
any queries
1. bool empty() const; Returns true if instance is empty, otherwise false. Throws Will not throw. 2. const std::type_info & type() const; Returns the typeid of the contained value if instance is nonempty, otherwise typeid(void). Notes Useful for querying against types known either at compile time or only at runtime.
Function any_cast boost::any_cast Custom keyword cast for extracting a value of a given type from an any.
Synopsis template<typename ValueType> ValueType any_cast(const any & operand); template<typename ValueType> const ValueType * any_cast(const any * operand); template<typename ValueType> ValueType * any_cast(any * operand);
Description
Returns If passed a pointer, it returns a similarly qualified pointer to the value content if successful, otherwise null is returned. If passed a value or reference, it returns a copy of the value content if successful. Throws Overloads taking an any pointer do not throw; the overload taking an any value or reference throws bad_any_cast if unsuccessful. Rationale
5
Chapter 1. Boost.Any
The value/reference version returns a copy because the C++ keyword casts return copies.
4. Acknowledgements
Doug Gregor ported the documentation to the BoostBook format.
Chapter 2. Boost.Array
Nicolai Josuttis Copyright 2001, 2002, 2003, 2004 Nicolai M. Josuttis
Permission to copy, use, modify, sell and distribute this software is granted provided this copyright notice appears in all copies. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
1. Introduction
The C++ Standard Template Library STL as part of the C++ Standard Library provides a framework for processing algorithms on different kind of containers. However, ordinary arrays don't provide the interface of STL containers (although, they provide the iterator interface of STL containers). As replacement for ordinary arrays, the STL provides class std::vector. However, std::vector<> provides the semantics of dynamic arrays. Thus, it manages data to be able to change the number of elements. This results in some overhead in case only arrays with static size are needed. In his book, Generic Programming and the STL, Matthew H. Austern introduces a useful wrapper class for ordinary arrays with static size, called block. It is safer and has no worse performance than ordinary arrays. In The C++ Programming Language, 3rd edition, Bjarne Stroustrup introduces a similar class, called c_array, which I (Nicolai Josuttis) present slightly modified in my book The C++ Standard Library A Tutorial and Reference, called carray. This is the essence of these approaches spiced with many feedback from boost. After considering different names, we decided to name this class simply array. Note that this class is suggested to be part of the next Technical Report, which will extend the C++ Standard (see http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1548.htm). Class array fulfills most but not all of the requirements of "reversible containers" (see Section 23.1, [lib.container.requirements] of the C++ Standard). The reasons array is not an reversible STL container is because: No constructors are provided. Elements may have an undetermined initial value (see Section 3, Design Rationale ). swap() has no constant complexity. size() is always constant, based on the second template argument of the type. The container provides no allocator support. It doesn't fulfill the requirements of a "sequence" (see Section 23.1.1, [lib.sequence.reqmts] of the C++ Standard), except that: front() and back() are provided. operator[] and at() are provided.
2. Reference
2.1. Header <boost/array.hpp>
namespace boost { template<typename T, std::size_t template<typename T, std::size_t template<typename T, std::size_t bool operator==(const array<T, N> class array; N> void swap(array<T, N>&, array<T, N>&); N> N>&, const array<T, N>&);
Chapter 2. Boost.Array
template<typename T, std::size_t N> bool operator!=(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator<(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator>(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator<=(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator>=(const array<T, N>&, const array<T, N>&); }
Class template array boost::array STL compliant container wrapper for arrays of constant size
Synopsis template<typename T, std::size_t N> class array { public: // types typedef T typedef T* typedef const T* typedef std::reverse_iterator<iterator> typedef std::reverse_iterator<const_iterator> typedef T& typedef const T& typedef std::size_t typedef std::ptrdiff_t // static constants static const size_type static_size = N; // construct/copy/destruct template<typename U> array& operator=(const array<U, N>&); // iterator support iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; // reverse iterator support reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const; // capacity size_type size(); bool empty(); size_type max_size(); // element access reference operator[](size_type); const_reference operator[](size_type) const; reference at(size_type); const_reference at(size_type) const; reference front(); const_reference front() const; reference back();
Chapter 2. Boost.Array
const_reference back() const; const T* data() const; T* c_array(); // modifiers void swap(array<T, N>&); void assign(const T&); T elems[N]; }; // specialized algorithms template<typename T, std::size_t N> void swap(array<T, N>&, array<T, N>&); // comparisons template<typename T, std::size_t N> bool operator==(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator!=(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator<(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator>(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator<=(const array<T, N>&, const array<T, N>&); template<typename T, std::size_t N> bool operator>=(const array<T, N>&, const array<T, N>&);
Description
array construct/copy/destruct
1. template<typename U> array& operator=(const array<U, N>& other); Effects std::copy(rhs.begin(),rhs.end(), begin())
1.
iterator begin(); const_iterator begin() const;
Returns iterator for the first element Throws will not throw 2.
iterator end(); const_iterator end() const;
Returns iterator for position after the last element Throws will not throw
Chapter 2. Boost.Array
array reverse iterator support
1.
reverse_iterator rbegin(); const_reverse_iterator rbegin() const;
Returns reverse iterator for position after the last element in reverse iteration
array capacity
1. size_type size(); Returns N 2. bool empty(); Returns N==0 Throws will not throw 3. size_type max_size(); Returns N Throws will not throw
1.
reference operator[](size_type i); const_reference operator[](size_type i) const;
Requires i < N Returns element with index i Throws will not throw. 2.
reference at(size_type i); const_reference at(size_type i) const;
10
Chapter 2. Boost.Array
Requires N > 0 Returns the first element Throws will not throw 4.
reference back(); const_reference back() const;
Requires N > 0 Returns the last element Throws will not throw 5. const T* data() const; Returns elems Throws will not throw 6. T* c_array(); Returns elems Throws will not throw
array modifiers
1. void swap(array<T, N>& other); Effects std::swap_ranges(begin(), end(), other.begin()) Complexity linear in N 2. void assign(const T& value); Effects std::fill_n(begin(), N, value)
1. template<typename T, std::size_t N> void swap(array<T, N>& x, array<T, N>& y); Effects x.swap(y) Throws will not throw.
array comparisons
11
Chapter 2. Boost.Array
3. Design Rationale
There was an important design tradeoff regarding the constructors: We could implement array as an "aggregate" (see Section 8.5.1, [dcl.init.aggr], of the C++ Standard). This would mean: An array can be initialized with a braceenclosing, commaseparated list of initializers for the elements of the container, written in increasing subscript order:
boost::array<int,4> a = { { 1, 2, 3 } };
Note that if there are fewer elements in the initializer list, then each remaining element gets defaultinitialized (thus, it has a defined value). However, this approach has its drawbacks: passing no initializer list means that the elements have an indetermined initial value, because the rule says that aggregates may have: No userdeclared constructors. No private or protected nonstatic data members. No base classes. No virtual functions. Nevertheless, The current implementation uses this approach. Note that for standard conforming compilers it is possible to use fewer braces (according to 8.5.1 (11) of the Standard). That is, you can initialize an array as follows:
boost::array<int,4> a = { 1, 2, 3 };
I'd appreciate any constructive feedback. Please note: I don't have time to read all boost mails. Thus, to make sure that feedback arrives to me, please send me a copy of each mail regarding this class.
12
Chapter 2. Boost.Array
5. Acknowledgements
Doug Gregor ported the documentation to the BoostBook format.
13
Chapter 3. Boost.Function
Douglas Gregor <dgregor at cs.indiana.edu> Copyright 2001, 2002, 2003, 2004 Douglas Gregor
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. Introduction
The Boost.Function library contains a family of class templates that are function object wrappers. The notion is similar to a generalized callback. It shares features with function pointers in that both define a call interface (e.g., a function taking two integer arguments and returning a floatingpoint value) through which some implementation can be called, and the implementation that is invoked may change throughout the course of the program. Generally, any place in which a function pointer would be used to defer a call or make a callback, Boost.Function can be used instead to allow the user greater flexibility in the implementation of the target. Targets can be any 'compatible' function object (or function pointer), meaning that the arguments to the interface designated by Boost.Function can be converted to the arguments of the target function object.
14
Chapter 3. Boost.Function
The invocation policy template parameter (Policy) has been deprecated and will be removed. There is no direct equivalent to this rarely used feature. The mixin template parameter (Mixin) has been deprecated and will be removed. There is not direct equivalent to this rarely used feature. The set methods have been deprecated and will be removed. Use the assignment operator instead.
3. Tutorial
Boost.Function has two syntactical forms: the preferred form and the portable form. The preferred form fits more closely with the C++ language and reduces the number of separate template parameters that need to be considered, often improving readability; however, the preferred form is not supported on all platforms due to compiler bugs. The compatible form will work on all compilers supported by Boost.Function. Consult the table below to determine which syntactic form to use for your compiler. Preferred syntax GNU C++ 2.95.x, 3.0.x, 3.1.x Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 Compaq's cxx 6.2 Microsoft Visual C++ 7.1 Portable syntax
Any compiler supporting the preferred syntax Microsoft Visual C++ 6.0, 7.0 Borland C++ 5.5.1 Sun WorkShop 6 update 2 C++ 5.3 Metrowerks CodeWarrior 8.1
If your compiler does not appear in this list, please try the preferred syntax and report your results to the Boost list so that we can keep this table uptodate.
Portable syntax
boost::function2<float, int, int> f;
By default, function object wrappers are empty, so we can create a function object to assign to f:
struct int_div { float operator()(int x, int y) const { return ((float)x)/y; }; }; f = int_div();
We are free to assign any compatible function object to f. If int_div had been declared to take two long operands, the implicit conversions would have been applied to the arguments without any user interference. The only limit on the types of arguments is that they be CopyConstructible, so we can even use references and arrays: Preferred syntax
15
Chapter 3. Boost.Function
boost::function<void (int values[], int n, int& sum, float& avg)> sum_avg;
Portable syntax
boost::function4<void, int*, int, int&, float&> sum_avg; void do_sum_avg(int values[], int n, int& sum, float& avg) { sum = 0; for (int i = 0; i < n; i++) sum += values[i]; avg = (float)sum / n; } sum_avg = &do_sum_avg;
Invoking a function object wrapper that does not actually contain a function object is a precondition violation, much like trying to call through a null function pointer, and will throw a bad_function_call exception). We can check for an empty function object wrapper by using it in a boolean context (it evaluates true if the wrapper is not empty) or compare it against 0. For instance:
if (f) std::cout << f(5, 3) << std::endl; else std::cout << "f has no target, so it is unsafe to call" << std::endl;
Alternatively, empty() method will return whether or not the wrapper is empty. Finally, we can clear out a function target by assigning it to 0 or by calling the clear() member function, e.g.,
f = 0;
Note that the & isn't really necessary unless you happen to be using Microsoft Visual C++ version 6.
Preferred syntax
boost::function<int (X*, int)> f; f = &X::foo;
Portable syntax
boost::function2<int, X*, int> f; f = &X::foo;
16
Chapter 3. Boost.Function
X x; f(&x, 5); X x; f(&x, 5);
Several libraries exist that support argument binding. Three such libraries are summarized below: Bind. This library allows binding of arguments for any function object. It is lightweight and very portable. The C++ Standard library. Using std::bind1st and std::mem_fun together one can bind the object of a pointertomember function for use with Boost.Function: Preferred syntax
boost::function<int (int)> f; X x; f = std::bind1st( std::mem_fun(&X::foo), &x); f(5); // Call x.foo(5)
Portable syntax
boost::function1<int, int> f; X x; f = std::bind1st( std::mem_fun(&X::foo), &x); f(5); // Call x.foo(5)
The Lambda library. This library provides a powerful composition mechanism to construct function objects that uses very natural C++ syntax. Lambda requires a compiler that is reasonably conformant to the C++ standard.
Portable syntax
stateful_type a_function_object; boost::function1<int, int> f; f = boost::ref(a_function_object); boost::function1<int, int> f2(f);
Here, f will not make a copy of a_function_object, nor will f2 when it is targeted to f's reference to a_function_object. Additionally, when using references to function objects, Boost.Function will not throw exceptions during assignment or construction.
When comparing against an instance of reference_wrapper, the address of the object in the reference_wrapper is compared against the address of the object stored by the function object wrapper:
a_stateful_object so1, so2; f = boost::ref(so1); assert(f == boost::ref(so1)); assert(f == so1); // Only if a_stateful_object is EqualityComparable assert(f != boost::ref(so2));
17
Chapter 3. Boost.Function
4. Reference
4.1. Definitions
A function object f is compatible if for the given set of argument types Arg1, Arg2, ..., ArgN and a return type ResultType, the appropriate following function is wellformed:
// if ResultType is not void ResultType foo(Arg1 arg1, Arg2 arg2, ..., ArgN argN) { return f(arg1, arg2, ..., argN); } // if ResultType is void ResultType foo(Arg1 arg1, Arg2 arg2, ..., ArgN argN) { f(arg1, arg2, ..., argN); }
A special provision is made for pointers to member functions. Though they are not function objects, Boost.Function will adapt them internally to function objects. This requires that a pointer to member function of the form R (X::*mf)(Arg1, Arg2, ..., ArgN) cvquals be adapted to a function object with the following function call operator overloads:
template<typename P> R operator()(cvquals P& x, Arg1 arg1, Arg2 arg2, ..., ArgN argN) const { return (*x).*mf(arg1, arg2, ..., argN); }
A function object f of type F is stateless if it is a function pointer or if boost::is_stateless<T> is true. The construction of or copy to a Boost.Function object from a stateless function object will not cause exceptions to be thrown and will not allocate any storage.
18
Chapter 3. Boost.Function
typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>&, Functor); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(Functor, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>&, reference_wrapper<Functor>); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(reference_wrapper<Functor>, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator1, typename U1, typename U2, ..., typename UN, typename Allocator2> void operator!=(const functionN<T1, T2, ..., TN, Allocator1>&, const functionN<U1, U2, ..., UN, Allocator2>&); template<typename Signature, typename Allocator = std::allocator<void> > class function; template<typename Signature, typename Allocator> void swap(function<Signature, Allocator>&, function<Signature, Allocator>&); template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>&, Functor); template<typename Signature, typename Allocator, typename Functor> bool operator==(Functor, const function<Signature, Allocator>&); template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>&, reference_wrapper<Functor>); template<typename Signature, typename Allocator, typename Functor> bool operator==(reference_wrapper<Functor>, const function<Signature, Allocator>&); template<typename Signature1, typename Allocator1, typename Signature2, typename Allocator2> void operator==(const function<Signature1, Allocator1>&, const function<Signature2, Allocator2>&); template<typename Signature, typename Allocator, typename Functor> bool operator!=(const function<Signature, Allocator>&, Functor); template<typename Signature, typename Allocator, typename Functor> bool operator!=(Functor, const function<Signature, Allocator>&); template<typename Signature, typename Allocator, typename Functor> bool operator!=(const function<Signature, Allocator>&, reference_wrapper<Functor>); template<typename Signature, typename Allocator, typename Functor> bool operator!=(reference_wrapper<Functor>, const function<Signature, Allocator>&); template<typename Signature1, typename Allocator1, typename Signature2, typename Allocator2> void operator!=(const function<Signature1, Allocator1>&, const function<Signature2, Allocator2>&); }
An exception type thrown when an instance of a function object is empty when invoked.
19
Chapter 3. Boost.Function
Description
bad_function_call construct/copy/destruct
The common base class for all Boost.Function objects. Objects of type function_base may not be
Description
function_base capacity
1. bool empty() const; Returns false if this has a target, and true otherwise. Throws Will not throw.
1.
template<typename Functor> Functor* target(); template<typename Functor> const Functor* target() const;
Returns If this stores a target of type Functor, returns the address of the target. Otherwise, returns the NULL pointer. Throws Will not throw. 2. template<typename Functor> bool contains(const Functor& f) const; Returns true if this>target<Functor>() is nonNULL and function_equal(*(this>target<Functor>()), f)
20
Chapter 3. Boost.Function
A set of generalized function pointers that can be used for callbacks or wrapping function objects.
21
Chapter 3. Boost.Function
template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(Functor, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(const functionN<T1, T2, ..., TN, Allocator>&, reference_wrapper<Functor>); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(reference_wrapper<Functor>, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator1, typename U1, typename U2, ..., typename UN, typename Allocator2> void operator==(const functionN<T1, T2, ..., TN, Allocator1>&, const functionN<U1, U2, ..., UN, Allocator2>&); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>&, Functor); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(Functor, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>&, reference_wrapper<Functor>); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(reference_wrapper<Functor>, const functionN<T1, T2, ..., TN, Allocator>&); template<typename T1, typename T2, ..., typename TN, typename Allocator1, typename U1, typename U2, ..., typename UN, typename Allocator2> void operator!=(const functionN<T1, T2, ..., TN, Allocator1>&, const functionN<U1, U2, ..., UN, Allocator2>&);
Description
Class template functionN is actually a family of related classes function0, function1, etc., up to some implementationdefined maximum. In this context, N refers to the number of parameters.
functionN construct/copy/destruct
1. functionN(); Postconditions this>empty() Throws Will not throw. 2. functionN(const functionN& f); Postconditions Contains a copy of the f's target, if it has one, or is empty if f.empty(). Throws Will not throw unless copying the target of f throws. 3. template<typename F> functionN(F f); Requires F is a function object Callable from this. Postconditions *this targets a copy of f if f is nonempty, or this>empty() if f is empty. Throws Will not throw when f is a stateless function object.
22
Chapter 3. Boost.Function
4. functionN& operator=(const functionN& f); Postconditions *this targets a copy of f's target, if it has one, or is empty if f.empty(). Throws Will not throw when the target of f is a stateless function object or a reference to the function object. 5. ~functionN(); Effects If !this>empty(), destroys the target of this.
functionN modifiers
1. void swap(const functionN& f); Effects Interchanges the targets of *this and f. Throws Will not throw. 2. void clear(); Postconditions this>empty() Throws Will not throw.
functionN capacity
1. bool empty() const; Returns false if this has a target, and true otherwise. Throws Will not throw. 2. operator safe_bool() const; Returns A safe_bool that evaluates false in a boolean context when this>empty(), and true otherwise. Throws Will not throw. 3. bool operator!() const; Returns this>empty() Throws Will not throw.
1.
template<typename Functor> Functor* target(); template<typename Functor> const Functor* target() const;
Returns
23
Chapter 3. Boost.Function
If this stores a target of type Functor, returns the address of the target. Otherwise, returns the NULL pointer. Throws Will not throw. 2. template<typename Functor> bool contains(const Functor& f) const; Returns true if this>target<Functor>() is nonNULL and function_equal(*(this>target<Functor>()), f)
functionN invocation
1. result_type operator()(arg1_type a1, arg2_type a2, ... , argN_type aN) const; Effects f(a1, a2, ..., aN), where f is the target of *this. Returns if R is void, nothing is returned; otherwise, the return value of the call to f is returned. Throws bad_function_call if !this>empty(). Otherwise, may through any exception thrown by the target function f.
1.
template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(const functionN<T1, T2, ..., TN, Allocator>& f, Functor g); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(Functor g, const functionN<T1, T2, ..., TN, Allocator>& f); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(const functionN<T1, T2, ..., TN, Allocator>& f, reference_wrapper<Functor> g); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator==(reference_wrapper<Functor> g, const functionN<T1, T2, ..., TN, Allocator>& f); template<typename T1, typename T2, ..., typename TN, typename Allocator1, typename U1, typename U2, ..., typename UN, typename Allocator2> void operator==(const functionN<T1, T2, ..., TN, Allocator1>& f1, const functionN<U1, U2, ..., UN, Allocator2>& f2);
Returns True when f stores an object of type Functor and one of the following conditions applies:
24
Chapter 3. Boost.Function
g is of type reference_wrapper<Functor> and f.target<Functor>() == g.get_pointer(). g is not of type reference_wrapper<Functor> and function_equal(*(f.target<Functor>()), g). Notes functionN objects are not EqualityComparable. Rationale The safe_bool conversion opens a loophole whereby two functionN instances can be compared via ==, although this is not feasible to implement. The undefined void operator== closes the loophole and ensures a compiletime or linktime error. 2.
template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>& f, Functor g); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(Functor g, const functionN<T1, T2, ..., TN, Allocator>& f); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(const functionN<T1, T2, ..., TN, Allocator>& f, reference_wrapper<Functor> g); template<typename T1, typename T2, ..., typename TN, typename Allocator, typename Functor> bool operator!=(reference_wrapper<Functor> g, const functionN<T1, T2, ..., TN, Allocator>& f); template<typename T1, typename T2, ..., typename TN, typename Allocator1, typename U1, typename U2, ..., typename UN, typename Allocator2> void operator!=(const functionN<T1, T2, ..., TN, Allocator1>& f1, const functionN<U1, U2, ..., UN, Allocator2>& f2);
Returns True when f does not store an object of type Functor or it stores an object of type Functor and one of the following conditions applies: g is of type reference_wrapper<Functor> and f.target<Functor>() != g.get_pointer(). g is not of type reference_wrapper<Functor> and !function_equal(*(f.target<Functor>()), g). Notes functionN objects are not EqualityComparable. Rationale The safe_bool conversion opens a loophole whereby two functionN instances can be compared via !=, although this is not feasible to implement. The undefined void operator!= closes the loophole and ensures a compiletime or linktime error.
A generalized function pointer that can be used for callbacks or wrapping function objects.
25
Chapter 3. Boost.Function
typedef T2 . . . typedef TN arg2_type;
argN_type;
// static constants static const int arity = N; // Lambda library support template<typename Args> struct sig { // types typedef result_type type; }; // construct/copy/destruct function(); function(const functionN&); function(const function&); template<typename F> function(F); function& operator=(const functionN&); function& operator=(const function&); ~function(); // modifiers void swap(const function&); void clear(); // capacity bool empty() const; operator safe_bool() const; bool operator!() const; // target access template<typename Functor> Functor* target(); template<typename Functor> const Functor* target() const; template<typename Functor> bool contains(const Functor&) const; // invocation result_type operator()(arg1_type, arg2_type, ..., argN_type) const; }; // specialized algorithms template<typename Signature, typename Allocator> void swap(function<Signature, Allocator>&, function<Signature, Allocator>&); // comparison operators template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>&, Functor); template<typename Signature, typename Allocator, typename Functor> bool operator==(Functor, const function<Signature, Allocator>&); template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>&, reference_wrapper<Functor>); template<typename Signature, typename Allocator, typename Functor> bool operator==(reference_wrapper<Functor>, const function<Signature, Allocator>&); template<typename Signature1, typename Allocator1, typename Signature2, typename Allocator2> void operator==(const function<Signature1, Allocator1>&, const function<Signature2, Allocator2>&); template<typename Signature, typename Allocator, typename Functor> bool operator!=(const function<Signature, Allocator>&, Functor); template<typename Signature, typename Allocator, typename Functor> bool operator!=(Functor, const function<Signature, Allocator>&); template<typename Signature, typename Allocator, typename Functor> bool operator!=(const function<Signature, Allocator>&,
26
Chapter 3. Boost.Function
reference_wrapper<Functor>); template<typename Signature, typename Allocator, typename Functor> bool operator!=(reference_wrapper<Functor>, const function<Signature, Allocator>&); template<typename Signature1, typename Allocator1, typename Signature2, typename Allocator2> void operator!=(const function<Signature1, Allocator1>&, const function<Signature2, Allocator2>&);
Description
Class template function is a thin wrapper around the numbered class templates function0, function1, etc. It accepts a function type with N arguments and will will derive from functionN instantiated with the arguments it receives. The semantics of all operations in class template function are equivalent to that of the underlying functionN object, although additional member functions are required to allow proper copy construction and copy assignment of function objects.
function construct/copy/destruct
1. function(); Postconditions this>empty() Throws Will not throw. 2. function(const functionN& f); Postconditions Contains a copy of the f's target, if it has one, or is empty if f.empty(). Throws Will not throw unless copying the target of f throws. 3. function(const function& f); Postconditions Contains a copy of the f's target, if it has one, or is empty if f.empty(). Throws Will not throw unless copying the target of f throws. 4. template<typename F> function(F f); Requires F is a function object Callable from this. Postconditions *this targets a copy of f if f is nonempty, or this>empty() if f is empty. Throws Will not throw when f is a stateless function object. 5. function& operator=(const functionN& f); Postconditions *this targets a copy of f's target, if it has one, or is empty if f.empty() Throws Will not throw when the target of f is a stateless function object or a reference to the function object. 6. function& operator=(const function& f); Postconditions *this targets a copy of f's target, if it has one, or is empty if f.empty() Throws Will not throw when the target of f is a stateless function object or a reference to the function object.
27
Chapter 3. Boost.Function
function modifiers
1. void swap(const function& f); Effects Interchanges the targets of *this and f. Throws Will not throw. 2. void clear(); Postconditions this>empty() Throws Will not throw.
function capacity
1. bool empty() const; Returns false if this has a target, and true otherwise. Throws Will not throw. 2. operator safe_bool() const; Returns A safe_bool that evaluates false in a boolean context when this>empty(), and true otherwise. Throws Will not throw. 3. bool operator!() const; Returns this>empty() Throws Will not throw.
1.
template<typename Functor> Functor* target(); template<typename Functor> const Functor* target() const;
Returns If this stores a target of type Functor, returns the address of the target. Otherwise, returns the NULL pointer. Throws Will not throw. 2. template<typename Functor> bool contains(const Functor& f) const; Returns
28
Chapter 3. Boost.Function
function invocation
1. result_type operator()(arg1_type a1, arg2_type a2, ... , argN_type aN) const; Effects f(a1, a2, ..., aN), where f is the target of *this. Returns if R is void, nothing is returned; otherwise, the return value of the call to f is returned. Throws bad_function_call if !this>empty(). Otherwise, may through any exception thrown by the target function f.
1.
template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>& f, Functor g); template<typename Signature, typename Allocator, typename Functor> bool operator==(Functor g, const function<Signature, Allocator>& f); template<typename Signature, typename Allocator, typename Functor> bool operator==(const function<Signature, Allocator>& f, reference_wrapper<Functor> g); template<typename Signature, typename Allocator, typename Functor> bool operator==(reference_wrapper<Functor> g, const function<Signature, Allocator>& f); template<typename Signature1, typename Allocator1, typename Signature2, typename Allocator2> void operator==(const function<Signature1, Allocator1>& f1, const function<Signature2, Allocator2>& f2);
Returns True when f stores an object of type Functor and one of the following conditions applies: g is of type reference_wrapper<Functor> and f.target<Functor>() == g.get_pointer(). g is not of type reference_wrapper<Functor> and function_equals(*(f.target<Functor>()), g). Notes function objects are not EqualityComparable. Rationale The safe_bool conversion opens a loophole whereby two function instances can be compared via ==, although this is not feasible to implement. The undefined void operator== closes the loophole and ensures a compiletime or linktime error.
29
Chapter 3. Boost.Function
Returns True when f does not store an object of type Functor or it stores an object of type Functor and one of the following conditions applies: g is of type reference_wrapper<Functor> and f.target<Functor>() != g.get_pointer(). g is not of type reference_wrapper<Functor> and !function_equals(*(f.target<Functor>()), g). Notes function objects are not EqualityComparable. Rationale The safe_bool conversion opens a loophole whereby two function instances can be compared via !=, although this is not feasible to implement. The undefined void operator!= closes the loophole and ensures a compiletime or linktime error.
Function template function_equal boost::function_equal Compare two function objects for equality.
Synopsis template<typename F, typename G> bool function_equal(const F& f, const G& g);
Description
Chapter 3. Boost.Function
5.4. Why (function) cloning? 5.5. How much overhead does a call through boost::function incur? 5.1. Why can't I compare boost::function objects with operator== or operator!=? Comparison between boost::function objects cannot be implemented "well", and therefore will not be implemented. The typical semantics requested for f == g given boost::function objects f and g are: If f and g store function objects of the same type, use that type's operator== to compare them. If f and g store function objects of different types, return false. The problem occurs when the type of the function objects stored by both f and g doesn't have an operator==: we would like the expression f == g to fail to compile, as occurs with, e.g., the standard containers. However, this is not implementable for boost::function because it necessarily "erases" some type information after it has been assigned a function object, so it cannot try to call operator== later: it must either find a way to call operator== now, or it will never be able to call it later. Note, for instance, what happens if you try to put a float value into a boost::function object: you will get an error at the assignment operator or constructor, not in operator(), because the functioncall expression must be bound in the constructor or assignment operator. The most promising approach is to find a method of determining if operator== can be called for a particular type, and then supporting it only when it is available; in other situations, an exception would be thrown. However, to date there is no known way to detect if an arbitrary operator expression f == g is suitably defined. The best solution known has the following undesirable qualities: 1. Fails at compiletime for objects where operator== is not accessible (e.g., because it is private). 2. Fails at compiletime if calling operator== is ambiguous. 3. Appears to be correct if the operator== declaration is correct, even though operator== may not compile. All of these problems translate into failures in the boost::function constructors or assignment operator, even if the user never invokes operator==. We can't do that to users. The other option is to place the burden on users that want to use operator==, e.g., by providing an is_equality_comparable trait they may specialize. This is a workable solution, but is dangerous in practice, because forgetting to specialize the trait will result in unexpected exceptions being thrown from boost::function's operator==. This essentially negates the usefulness of operator== in the context in which it is most desired: multitarget callbacks. The Signals library has a way around this. 5.2. I see void pointers; is this [mess] type safe? Yes, boost::function is type safe even though it uses void pointers and pointers to functions returning void and taking no arguments. Essentially, all type information is encoded in the functions that manage and invoke function pointers and function objects. Only these functions are instantiated with the exact type that is pointed to by the void pointer or pointer to void function. The reason that both are required is that one may cast between void pointers and object pointers safely or between different types of function pointers (provided you don't invoke a function pointer with the wrong type). 5.3. Why are there workarounds for void returns? C++ allows them! Void returns are permitted by the C++ standard, as in this code snippet:
void f(); void g() { return f(); }
This is a valid usage of boost::function because void returns are not used. With void returns, we would attempting to compile illformed code similar to:
int f(); void g() { return f(); }
31
Chapter 3. Boost.Function
In essence, not using void returns allows boost::function to swallow a return value. This is consistent with allowing the user to assign and invoke functions and function objects with parameters that don't exactly match. 5.4. Why (function) cloning? In November and December of 2000, the issue of cloning vs. reference counting was debated at length and it was decided that cloning gave more predictable semantics. I won't rehash the discussion here, but if it cloning is incorrect for a particular application a referencecounting allocator could be used. 5.5. How much overhead does a call through boost::function incur? The cost of boost::function can be reasonably consistently measured at around 20ns +/ 10 ns on a modern >2GHz platform versus directly inlining the code. However, the performance of your application may benefit from or be disadvantaged by boost::function depending on how your C++ optimiser optimises. Similar to a standard function pointer, differences of order of 10% have been noted to the benefit or disadvantage of using boost::function to call a function that contains a tight loop depending on your compilation circumstances. [Answer provided by Matt Hurd. See http://article.gmane.org/gmane.comp.lib.boost.devel/33278]
6. Miscellaneous Notes
6.1. Boost.Function vs. Function Pointers
Boost.Function has several advantages over function pointers, namely: Boost.Function allows arbitrary compatible function objects to be targets (instead of requiring an exact function signature). Boost.Function may be used with argumentbinding and other function object construction libraries. Boost.Function has predictible behavior when an empty function object is called. And, of course, function pointers have several advantages over Boost.Function: Function pointers are smaller (the size of one pointer instead of three) Function pointers are faster (Boost.Function may require two calls through function pointers) Function pointers are backwardcompatible with C libraries. More readable error messages.
6.2. Performance
6.2.1. Function object wrapper size Function object wrappers will be the size of two function pointers plus one function pointer or data pointer (whichever is larger). On common 32bit platforms, this amounts to 12 bytes per wrapper. Additionally, the function object target will be allocated on the heap. 6.2.2. Copying efficiency Copying function object wrappers may require allocating memory for a copy of the function object target. The default allocator may be replaced with a faster custom allocator or one may choose to allow the function object wrappers to only store function object targets by reference (using ref) if the cost of this cloning becomes prohibitive. 6.2.3. Invocation efficiency With a properly inlining compiler, an invocation of a function object requires one call through a function pointer. If the call is to a free function pointer, an additional call must be made to that function pointer (unless the compiler has very powerful interprocedural analysis).
32
Chapter 3. Boost.Function
6.4. Acknowledgements
Many people were involved in the construction of this library. William Kempf, Jesse Jones and Karl Nelson were all extremely helpful in isolating an interface and scope for the library. John Maddock managed the formal review, and many reviewers gave excellent comments on interface, implementation, and documentation. Peter Dimov led us to the function declaratorbased syntax.
7. Testsuite
7.1. Acceptance tests
Test Type Description If failing... The boost::function class template may not be usable on your compiler. However, the library may still be usable via the boost::functionN class templates.
function_test.cpp
run
function_n_test.cpp
run
Test the capabilities of the boost::functionN class templates. Test the use of custom allocators. Allocators are ignored by the implementation.
allocator_test.cpp
run
stateless_test.cpp
run
The exceptionsafety and Test the optimization of stateless performance guarantees given for function objects in the stateless function objects may not be Boost.Function library. met by the implementation. Test the interaction between Boost.Function and Boost.Lambda. Test the operation of the target member function and the equality operators. Test the generation of a Boost.Function function object adaptor accepting 30 arguments. The Boost.Function library may work for function object adaptors of up to 10 parameters, but will be unable to
33
lambda_test.cpp
run
Either Boost.Lambda does not work on the platform, or Boost.Function cannot safely be applied without the use of boost::unlambda.
contains_test.cpp function_30.cpp
run compile
Chapter 3. Boost.Function
generate adaptors for an arbitrary number of parameters. Failure often indicates an error in the compiler's preprocessor. function_arith_cxx98.cpp function_arith_portable.cpp sum_avg_cxx98.cpp sum_avg_portable.cpp mem_fun_cxx98.cpp mem_fun_portable.cpp std_bind_cxx98.cpp std_bind_portable.cpp function_ref_cxx98.cpp function_ref_portable.cpp run run run run run run run run run run Test the first tutorial example. Test the first tutorial example. Test the second tutorial example. Test the second tutorial example. Test member function example from tutorial. Test member function example from tutorial. Test standard binders example from tutorial. Test standard binders example from tutorial. Test boost::ref example from tutorial. Test boost::ref example from tutorial.
function_test_fail1.cpp compilefail
function_test_fail2.cpp compilefail
34
Chapter 4. Boost.Lambda
Jaakko Jrvi <jarvi at cs tamu edu> Copyright 1999, 2000, 2001, 2002, 2003, 2004 Jaakko Jrvi, Gary Powell
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. In a nutshell
The Boost Lambda Library (BLL in the sequel) is a C++ template library, which implements form of lambda abstractions for C++. The term originates from functional programming and lambda calculus, where a lambda abstraction defines an unnamed function. The primary motivation for the BLL is to provide flexible and convenient means to define unnamed function objects for STL algorithms. In explaining what the library is about, a line of code says more than a thousand words; the following line outputs the elements of some STL container a separated by spaces:
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
The expression std::cout << _1 << ' ' defines a unary function object. The variable _1 is the parameter of this function, a placeholder for the actual argument. Within each iteration of for_each, the function is called with an element of a as the actual argument. This actual argument is substituted for the placeholder, and the body of the function is evaluated. The essence of BLL is letting you define small unnamed function objects, such as the one above, directly on the call site of an STL algorithm.
2. Getting Started
2.1. Installing the library
The library consists of include files only, hence there is no installation procedure. The boost include directory must be on the include path. There are a number of include files that give different functionality: lambda/lambda.hpp defines lambda expressions for different C++ operators, see Section 5.2, Operator expressions . lambda/bind.hpp defines bind functions for up to 9 arguments, see Section 5.3, Bind expressions . lambda/if.hpp defines lambda function equivalents for if statements and the conditional operator, see Section 5.6, Lambda expressions for control structures (includes lambda.hpp). lambda/loops.hpp defines lambda function equivalent for looping constructs, see Section 5.6, Lambda expressions for control structures . lambda/switch.hpp defines lambda function equivalent for the switch statement, see Section 5.6, Lambda expressions for control structures . lambda/construct.hpp provides tools for writing lambda expressions with constructor, destructor, new and delete invocations, see Section 5.8, Construction and destruction (includes lambda.hpp). lambda/casts.hpp provides lambda versions of different casts, as well as sizeof and typeid, see Section 5.10.1, Cast expressions . lambda/exceptions.hpp gives tools for throwing and catching exceptions within lambda functions, Section 5.7, Exceptions (includes lambda.hpp). lambda/algorithm.hpp and lambda/numeric.hpp (cf. standard algortihm and numeric headers) allow nested STL algorithm invocations, see Section 5.11, Nesting STL algorithm invocations .
35
Chapter 4. Boost.Lambda
Any other header files in the package are for internal use. Additionally, the library depends on two other Boost Libraries, the Tuple[tuple] and the type_traits[type_traits] libraries, and on the boost/ref.hpp header. All definitions are placed in the namespace boost::lambda and its subnamespaces.
3. Introduction
3.1. Motivation
The Standard Template Library (STL) [STL94], now part of the C++ Standard Library [C++98], is a generic container and algorithm library. Typically STL algorithms operate on container elements via function objects. These function objects are passed as arguments to the algorithms. Any C++ construct that can be called with the function call syntax is a function object. The STL contains predefined function objects for some common cases (such as plus, less and not1). As an example, one possible implementation for the standard plus template is:
template <class T> : public binary_function<T, T, T> struct plus { T operator()(const T& i, const T& j) const { return i + j; } };
The base class binary_function<T, T, T> contains typedefs for the argument and return types of the function object, which are needed to make the function object adaptable. In addition to the basic function object classes, such as the one above, the STL contains binder templates for creating a unary function object from an adaptable binary function object by fixing one of the arguments to a constant value. For example, instead of having to explicitly write a function object class like:
class plus_1 { int _i; public: plus_1(const int& i) : _i(i) {} int operator()(const int& j) { return _i + j; } };
the equivalent functionality can be achieved with the plus template and one of the binder templates (bind1st). E.g., the following two expressions create function objects with identical functionalities; when invoked, both return the result of adding 1 to the argument of the function object:
plus_1(1) bind1st(plus<int>(), 1)
The subexpression plus<int>() in the latter line is a binary function object which computes the sum of two integers, and bind1st invokes this function object partially binding the first argument to 1. As an example of using the above function object, the following code adds 1 to each element of some container a and outputs the results into the standard output stream
36
Chapter 4. Boost.Lambda
cout.
transform(a.begin(), a.end(), ostream_iterator<int>(cout), bind1st(plus<int>(), 1));
To make the binder templates more generally applicable, the STL contains adaptors for making pointers or references to functions, and pointers to member functions, adaptable. Finally, some STL implementations contain function composition operations as extensions to the standard [SGI02]. All these tools aim at one goal: to make it possible to specify unnamed functions in a call of an STL algorithm, in other words, to pass code fragments as an argument to a function. However, this goal is attained only partially. The simple example above shows that the definition of unnamed functions with the standard tools is cumbersome. Complex expressions involving functors, adaptors, binders and function composition operations tend to be difficult to comprehend. In addition to this, there are significant restrictions in applying the standard tools. E.g. the standard binders allow only one argument of a binary function to be bound; there are no binders for 3ary, 4ary etc. functions. The Boost Lambda Library provides solutions for the problems described above: Unnamed functions can be created easily with an intuitive syntax. The above example can be written as:
transform(a.begin(), a.end(), ostream_iterator<int>(cout), 1 + _1);
Most of the restrictions in argument binding are removed, arbitrary arguments of practically any C++ function can be bound. Separate function composition operations are not needed, as function composition is supported implicitly.
A lambda expression defines an unnamed function and consists of: the parameters of this function: x1 ... xn. the expression e which computes the value of the function in terms of the parameters x1 ... xn. A simple example of a lambda expression is
lambda x y.x+y
Applying the lambda function means substituting the formal parameters with the actual arguments:
(lambda x y.x+y) 2 3 = 2 + 3 = 5
In the C++ version of lambda expressions the lambda x1 ... xn part is missing and the formal parameters have predefined names. In the current version of the library, there are three such predefined formal parameters, called placeholders: _1, _2 and _3. They refer to the first, second and third argument of the function defined by the lambda expression. For example, the C++ version of the definition
lambda x y.x+y
is
37
Chapter 4. Boost.Lambda
_1 + _2
Hence, there is no syntactic keyword for C++ lambda expressions. The use of a placeholder as an operand implies that the operator invocation is a lambda expression. However, this is true only for operator invocations. Lambda expressions containing function calls, control structures, casts etc. require special syntactic constructs. Most importantly, function calls need to be wrapped inside a bind function. As an example, consider the lambda expression:
lambda x y.foo(x,y)
Rather than foo(_1, _2), the C++ counterpart for this expression is:
bind(foo, _1, _2)
We refer to this type of C++ lambda expressions as bind expressions. A lambda expression defines a C++ function object, hence function application syntax is like calling any other function object, for instance: (_1 + _2)(i, j). 3.2.1. Partial function application A bind expression is in effect a partial function application. In partial function application, some of the arguments of a function are bound to fixed values. The result is another function, with possibly fewer arguments. When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments. 3.2.2. Terminology A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, a functor, when evaluated. We use the name lambda functor to refer to such a function object. Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor.
The expression _1 = 1 creates a lambda functor which assigns the value 1 to every element in v.[1] Next, we create a container of pointers and make them point to the elements in the first container v:
vector<int*> vp(10); transform(v.begin(), v.end(), vp.begin(), &_1);
The expression &_1 creates a function object for getting the address of each element in v. The addresses get assigned to the corresponding elements in vp. The next code fragment changes the values in v. For each element, the function foo is called. The original value of the element is passed as an argument to foo. The result of foo is assigned back to the element:
38
Chapter 4. Boost.Lambda
int foo(int); for_each(v.begin(), v.end(), _1 = bind(foo, _1));
In this call to sort, we are sorting the elements by their contents in descending order. Finally, the following for_each call outputs the sorted content of vp separated by line breaks:
for_each(vp.begin(), vp.end(), cout << *_1 << '\n');
Note that a normal (nonlambda) expression as subexpression of a lambda expression is evaluated immediately. This may cause surprises. For instance, if the previous example is rewritten as
for_each(vp.begin(), vp.end(), cout << '\n' << *_1);
the subexpression cout << '\n' is evaluated immediately and the effect is to output a single line break, followed by the elements of vp. The BLL provides functions constant and var to turn constants and, respectively, variables into lambda expressions, and can be used to prevent the immediate evaluation of subexpressions:
for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);
These functions are described more thoroughly in Section 5.5, Delaying constants and variables
The following lambda function invocation fails, since the return type cannot be deduced:
A a; B b; (_1 + _2)(a, b);
There are two alternative solutions to this. The first is to extend the BLL type deduction system to cover your own types (see Section 6, Extending return type deduction system ). The second is to use a special lambda expression (ret) which defines the return type in place (see Section 5.4, Overriding the deduced return type ):
A a; B b; ret<C>(_1 + _2)(a, b);
For bind expressions, the return type can be defined as a template argument of the bind function as well:
bind<int>(foo, _1, _2);
39
Chapter 4. Boost.Lambda
This restriction is not as bad as it may look. Since the lambda functors are most often called inside STLalgorithms, the arguments originate from dereferencing iterators and the dereferencing operators seldom return rvalues. And for the cases where they do, there are workarounds discussed in Section 5.9.2, Rvalues as actual arguments to lambda functors .
The comma operator is overloaded to combine lambda expressions into a sequence; the resulting unary lambda functor first assigns 2 to its argument, then adds the value of i to it. The value of the expression in the last line is 3, not 4. In other words, the lambda expression that is created is lambda x.(x = 2, x + 1) rather than lambda x.(x = 2, x + i). As said, this is the default behavior for which there are exceptions. The exact rules are as follows: The programmer can control the storing mechanism with ref and cref wrappers [ref]. Wrapping an argument with ref, or cref, instructs the library to store the argument as a reference, or as a reference to const respectively. For example, if we rewrite the previous example and wrap the variable i with ref, we are creating the lambda expression lambda x.(x = 2, x + i) and the value of the expression in the last line will be 4:
i = 1; (_1 = 2, _1 + ref(i))(i);
Note that ref and cref are different from var and constant. While the latter ones create lambda functors, the former do not. For example:
int i; var(i) = 1; // ok ref(i) = 1; // not ok, ref(i) is not a lambda functor
The functions ref and cref mostly exist for historical reasons, and ref can always be replaced with var, and cref with constant_ref. See Section 5.5, Delaying constants and variables for details. The ref and cref functions are general purpose utility functions in Boost, and hence defined directly in the boost namespace. Array types cannot be copied, they are thus stored as const reference by default. For some expressions it makes more sense to store the arguments as references. For example, the obvious intention of the lambda expression i += _1 is that calls to the lambda functor affect the value of the variable i, rather than some temporary copy of it. As another example, the streaming operators take their leftmost argument as nonconst references. The exact rules are: The left argument of compound assignment operators (+=, *=, etc.) are stored as references to nonconst. If the left argument of << or >> operator is derived from an instantiation of basic_ostream or respectively from basic_istream, the argument is stored as a reference to nonconst. For all other types, the argument is stored as a copy. In pointer arithmetic expressions, nonconst array types are stored as nonconst references. This is to prevent pointer arithmetic making nonconst arrays const.
40
Chapter 4. Boost.Lambda
5.1. Placeholders
The BLL defines three placeholder types: placeholder1_type, placeholder2_type and placeholder3_type. BLL has a predefined placeholder variable for each placeholder type: _1, _2 and _3. However, the user is not forced to use these placeholders. It is easy to define placeholders with alternative names. This is done by defining new variables of placeholder types. For example:
boost::lambda::placeholder1_type X; boost::lambda::placeholder2_type Y; boost::lambda::placeholder3_type Z;
With these variables defined, X += Y * Z is equivalent to _1 += _2 * _3. The use of placeholders in the lambda expression determines whether the resulting function is nullary, unary, binary or 3ary. The highest placeholder index is decisive. For example:
_1 + 5 // _1 * _1 + _1 // _1 + _2 // bind(f, _1, _2, _3) // _3 + 10 // unary unary binary 3ary 3ary
Note that the last line creates a 3ary function, which adds 10 to its third argument. The first two arguments are discarded. Furthermore, lambda functors only have a minimum arity. One can always provide more arguments (up the number of supported placeholders) that is really needed. The remaining arguments are just discarded. For example:
int i, j, k; _1(i, j, k) // returns i, discards j and k (_2 + _2)(i, j, k) // returns j+j, discards i and k
See Section 1,
In addition to these three placeholder types, there is also a fourth placeholder type placeholderE_type. The use of this placeholder is defined in Section 5.7, Exceptions describing exception handling in lambda expressions. When an actual argument is supplied for a placeholder, the parameter passing mode is always by reference. This means that any sideeffects to the placeholder are reflected to the actual argument. For example:
int i = 1; (_1 += 2)(i); // i is now 3 (++_1, cout << _1)(i) // i is now 4, outputs 4
However, there are some restrictions that originate from the C++ operator overloading rules, and some special cases.
41
Chapter 4. Boost.Lambda
5.2.1. Operators that cannot be overloaded Some operators cannot be overloaded at all (::, ., .*). For some operators, the requirements on return types prevent them to be overloaded to create lambda functors. These operators are >., >, new, new[], delete, delete[] and ?: (the conditional operator). 5.2.2. Assignment and subscript operators These operators must be implemented as class members. Consequently, the left operand must be a lambda expression. For example:
int i; _1 = i; i = _1;
There is a simple solution around this limitation, described in Section 5.5, Delaying constants and variables . In short, the left hand argument can be explicitly turned into a lambda functor by wrapping it with a special var function:
var(i) = _1; // ok
5.2.3. Logical operators Logical operators obey the shortcircuiting evaluation rules. For example, in the following code, i is never incremented:
bool flag = true; int i = 0; (_1 || ++_2)(flag, i);
5.2.4. Comma operator Comma operator is the statement separator in lambda expressions. Since comma is also the separator between arguments in a function call, extra parenthesis are sometimes needed:
for_each(a.begin(), a.end(), (++_1, cout << _1));
Without the extra parenthesis around ++_1, cout << _1, the code would be interpreted as an attempt to call for_each with four arguments. The lambda functor created by the comma operator adheres to the C++ rule of always evaluating the left operand before the right one. In the above example, each element of a is first incremented, then written to the stream. 5.2.5. Function call operator The function call operators have the effect of evaluating the lambda functor. Calls with too few arguments lead to a compile time error. 5.2.6. Member pointer operator The member pointer operator operator>* can be overloaded freely. Hence, for user defined types, member pointer operator is no special case. The builtin meaning, however, is a somewhat more complicated case. The builtin member pointer operator is applied if the left argument is a pointer to an object of some class A, and the right hand argument is a pointer to a member of A, or a pointer to a member of a class from which A derives. We must separate two cases: The right hand argument is a pointer to a data member. In this case the lambda functor simply performs the argument substitution and calls the builtin member pointer operator, which returns a reference to the member pointed to. For example:
struct A { int d; }; A* a = new A();
42
Chapter 4. Boost.Lambda
... (a >* &A::d); // returns a reference to a>d (_1 >* &A::d)(a); // likewise
The right hand argument is a pointer to a member function. For a builtin call like this, the result is kind of a delayed member function call. Such an expression must be followed by a function argument list, with which the delayed member function call is performed. For example:
struct B { int foo(int); }; B* b = new B(); ... (b >* &B::foo) // returns a delayed call to b>foo // a function argument list must follow (b >* &B::foo)(1) // ok, calls b>foo(1) (_1 >* &B::foo)(b); // returns a delayed call to b>foo, // no effect as such (_1 >* &B::foo)(b)(1); // calls b>foo(1)
A bind expression delays the call of a function. If this target function is nary, then the bindargumentlist must contain n arguments as well. In the current version of the BLL, 0 <= n <= 9 must hold. For member functions, the number of arguments must be at most 8, as the object argument takes one argument position. Basically, the bindargumentlist must be a valid argument list for the target function, except that any argument can be replaced with a placeholder, or more generally, with a lambda expression. Note that also the target function can be a lambda expression. The result of a bind expression is either a nullary, unary, binary or 3ary function object depending on the use of placeholders in the bindargumentlist (see Section 5.1, Placeholders ). The return type of the lambda functor created by the bind expression can be given as an explicitly specified template parameter, as in the following example:
bind<RET>(targetfunction, bindargumentlist)
This is only necessary if the return type of the target function cannot be deduced. The following sections describe the different types of bind expressions. 5.3.1. Function pointers or references as targets The target function can be a pointer or a reference to a function and it can be either bound or unbound. For example:
X foo(A, B, C); A a; B b; C c; bind(foo, _1, _2, c)(a, b); bind(&foo, _1, _2, c)(a, b); bind(_1, a, b, c)(foo);
The return type deduction always succeeds with this type of bind expressions. Note, that in C++ it is possible to take the address of an overloaded function only if the address is assigned to, or used as an initializer of, a variable, the type of which solves the amibiguity, or if an explicit cast expression is used. This means that overloaded functions cannot be used in bind expressions directly, e.g.:
void foo(int); void foo(float); int i;
43
Chapter 4. Boost.Lambda
... bind(&foo, _1)(i); // error ... void (*pf1)(int) = &foo; bind(pf1, _1)(i); // ok bind(static_cast<void(*)(int)>(&foo), _1)(i); // ok
5.3.2. Member functions as targets The syntax for using pointers to member function in bind expression is:
bind(targetmemberfunction, objectargument, bindargumentlist)
The object argument can be a reference or pointer to the object, the BLL supports both cases with a uniform interface:
bool A::foo(int) const; A a; vector<int> ints; ... find_if(ints.begin(), ints.end(), bind(&A::foo, a, _1)); find_if(ints.begin(), ints.end(), bind(&A::foo, &a, _1));
Similarly, if the object argument is unbound, the resulting lambda functor can be called both via a pointer or a reference:
bool A::foo(int); list<A> refs; list<A*> pointers; ... find_if(refs.begin(), refs.end(), bind(&A::foo, _1, 1)); find_if(pointers.begin(), pointers.end(), bind(&A::foo, _1, 1));
Even though the interfaces are the same, there are important semantic differences between using a pointer or a reference as the object argument. The differences stem from the way bindfunctions take their parameters, and how the bound parameters are stored within the lambda functor. The object argument has the same parameter passing and storing mechanism as any other bind argument slot (see Section 4.4, Storing bound arguments in lambda functions ); it is passed as a const reference and stored as a const copy in the lambda functor. This creates some asymmetry between the lambda functor and the original member function, and between seemingly similar lambda functors. For example:
class A { int i; mutable int j; public: A(int ii, int jj) : i(ii), j(jj) {}; void set_i(int x) { i = x; }; void set_j(int x) const { j = x; }; };
When a pointer is used, the behavior is what the programmer might expect:
A a(0,0); int k = 1; bind(&A::set_i, &a, _1)(k); // a.i == 1 bind(&A::set_j, &a, _1)(k); // a.j == 1
Even though a const copy of the object argument is stored, the original object a is still modified. This is since the object argument is a pointer, and the pointer is copied, not the object it points to. When we use a reference, the behaviour is different:
A a(0,0); int k = 1; bind(&A::set_i, a, _1)(k); // error; a const copy of a is stored. // Cannot call a nonconst function set_i bind(&A::set_j, a, _1)(k); // a.j == 0, as a copy of a is modified
44
Chapter 4. Boost.Lambda
To prevent the copying from taking place, one can use the ref or cref wrappers (var and constant_ref would do as well):
bind(&A::set_i, ref(a), _1)(k); // a.j == 1 bind(&A::set_j, cref(a), _1)(k); // a.j == 1
Note that the preceding discussion is relevant only for bound arguments. If the object argument is unbound, the parameter passing mode is always by reference. Hence, the argument a is not copied in the calls to the two lambda functors below:
A a(0,0); bind(&A::set_i, _1, 1)(a); // a.i == 1 bind(&A::set_j, _1, 1)(a); // a.j == 1
5.3.3. Member variables as targets A pointer to a member variable is not really a function, but the first argument to the bind function can nevertheless be a pointer to a member variable. Invoking such a bind expression returns a reference to the data member. For example:
struct A { int data; }; A a; bind(&A::data, _1)(a) = 1;
// a.data == 1
The cvqualifiers of the object whose member is accessed are respected. For example, the following tries to write into a const location:
const A ca = a; bind(&A::data, _1)(ca) = 1;
// error
5.3.4. Function objects as targets Function objects, that is, class objects which have the function call operator defined, can be used as target functions. In general, BLL cannot deduce the return type of an arbitrary function object. However, there are two methods for giving BLL this capability for a certain function object class.
The result_type typedef
The BLL supports the standard library convention of declaring the return type of a function object with a member typedef named result_type in the function object class. Here is a simple example:
struct A { typedef B result_type; B operator()(X, Y, Z); };
If a function object does not define a result_type typedef, the method described below (sig template) is attempted to resolve the return type of the function object. If a function object defines both result_type and sig, result_type takes precedence.
The sig template
Another mechanism that make BLL aware of the return type(s) of a function object is defining member template struct sig<Args> with a typedef type that specifies the return type. Here is a simple example:
struct A { template <class Args> struct sig { typedef B type; } B operator()(X, Y, Z); };
The template argument Args is a tuple (or more precisely a cons list) type [tuple], where the first element is the function object type itself, and the remaining elements are the types of the arguments, with which the function object is being called.
45
Chapter 4. Boost.Lambda
This may seem overly complex compared to defining the result_type typedef. Howver, there are two significant restrictions with using just a simple typedef to express the return type: 1. If the function object defines several function call operators, there is no way to specify different result types for them. 2. If the function call operator is a template, the result type may depend on the template parameters. Hence, the typedef ought to be a template too, which the C++ language does not support. The following code shows an example, where the return type depends on the type of one of the arguments, and how that dependency can be expressed with the sig template:
struct A { // the return type equals the third argument type: template<class T1, class T2, class T3> T3 operator()(const T1& t1, const T2& t2, const T3& t3) const; template <class Args> class sig { // get the third argument type (4th element) typedef typename boost::tuples::element<3, Args>::type T3; public: typedef typename boost::remove_cv<T3>::type type; }; };
The elements of the Args tuple are always nonreference types. Moreover, the element types can have a const or volatile qualifier (jointly referred to as cvqualifiers), or both. This is since the cvqualifiers in the arguments can affect the return type. The reason for including the potentially cvqualified function object type itself into the Args tuple, is that the function object class can contain both const and nonconst (or volatile, even const volatile) function call operators, and they can each have a different return type. The sig template can be seen as a metafunction that maps the argument type tuple to the result type of the call made with arguments of the types in the tuple. As the example above demonstrates, the template can end up being somewhat complex. Typical tasks to be performed are the extraction of the relevant types from the tuple, removing cvqualifiers etc. See the Boost type_traits [type_traits] and Tuple [type_traits] libraries for tools that can aid in these tasks. The sig templates are a refined version of a similar mechanism first introduced in the FC++ library [fc++].
The effect is that the return type deduction is not performed for the lambda expression e at all, but instead, T is used as the return type. Obviously T cannot be an arbitrary type, the true result of the lambda functor must be implicitly convertible to T. For example:
A a; B b; C operator+(A, B); int operator*(A, B); ... ret<D>(_1 + _2)(a, b); // error (C cannot be converted to D) ret<C>(_1 + _2)(a, b); // ok ret<float>(_1 * _2)(a, b); // ok (int can be converted to float) ...
46
Chapter 4. Boost.Lambda
struct X { Y operator(int)(); }; ... X x; int i; bind(x, _1)(i); ret<Y>(bind(x, _1))(i);
For bind expressions, there is a shorthand notation that can be used instead of ret. The last line could alternatively be written as:
bind<Z>(x, _1)(i);
This feature is modeled after the Boost Bind library [bind]. Note that within nested lambda expressions, the ret must be used at each subexpression where the deduction would otherwise fail. For example:
A a; B b; C operator+(A, B); D operator(C); ... ret<D>( (_1 + _2))(a, b); // error ret<D>( ret<C>(_1 + _2))(a, b); // ok
If you find yourself using ret repeatedly with the same types, it is worth while extending the return type deduction (see Section 6, Extending return type deduction system ). 5.4.1. Nullary lambda functors and ret As stated above, the effect of ret is to prevent the return type deduction to be performed. However, there is an exception. Due to the way the C++ template instantiation works, the compiler is always forced to instantiate the return type deduction templates for zeroargument lambda functors. This introduces a slight problem with ret, best described with an example:
struct F { int operator()(int i) const; }; F f; ... bind(f, _1); // fails, cannot deduce the return type ret<int>(bind(f, _1)); // ok ... bind(f, 1); // fails, cannot deduce the return type ret<int>(bind(f, 1)); // fails as well!
The BLL cannot deduce the return types of the above bind calls, as F does not define the typedef result_type. One would expect ret to fix this, but for the nullary lambda functor that results from a bind expression (last line above) this does not work. The return type deduction templates are instantiated, even though it would not be necessary and the result is a compilation error. The solution to this is not to use the ret function, but rather define the return type as an explicitly specified template parameter in the bind call:
bind<int>(f, 1); // ok
The lambda functors created with ret<T>(bind(arglist)) and bind<T>(arglist) have the exact same functionality apart from the fact that for some nullary lambda functors the former does not work while the latter does.
Chapter 4. Boost.Lambda
for_each(a.begin(), a.end(), cout << _1 << ' '); for_each(a.begin(), a.end(), cout << ' ' << _1);
The first line outputs the elements of a separated by spaces, while the second line outputs a space followed by the elements of a without any separators. The reason for this is that neither of the operands of cout << ' ' is a lambda expression, hence cout << ' ' is evaluated immediately. To delay the evaluation of cout << ' ', one of the operands must be explicitly marked as a lambda expression. This is accomplished with the constant function:
for_each(a.begin(), a.end(), cout << constant(' ') << _1);
The call constant(' ') creates a nullary lambda functor which stores the character constant ' ' and returns a reference to it when invoked. The function constant_ref is similar, except that it stores a constant reference to its argument. The constant and consant_ref are only needed when the operator call has side effects, like in the above example. Sometimes we need to delay the evaluation of a variable. Suppose we wanted to output the elements of a container in a numbered list:
int index = 0; for_each(a.begin(), a.end(), cout << ++index << ':' << _1 << '\n'); for_each(a.begin(), a.end(), cout << ++var(index) << ':' << _1 << '\n');
The first for_each invocation does not do what we want; index is incremented only once, and its value is written into the output stream only once. By using var to make index a lambda expression, we get the desired effect. In sum, var(x) creates a nullary lambda functor, which stores a reference to the variable x. When the lambda functor is invoked, a reference to x is returned. Naming delayed constants and variables It is possible to predefine and name a delayed variable or constant outside a lambda expression. The templates var_type, constant_type and constant_ref_type serve for this purpose. They are used as:
var_type<T>::type delayed_i(var(i)); constant_type<T>::type delayed_c(constant(c));
The first line defines the variable delayed_i which is a delayed version of the variable i of type T. Analogously, the second line defines the constant delayed_c as a delayed version of the constant c. For example:
int i = 0; int j; for_each(a.begin(), a.end(), (var(j) = _1, _1 = var(i), var(i) = var(j)));
is equivalent to:
int i = 0; int j; var_type<int>::type vi(var(i)), vj(var(j)); for_each(a.begin(), a.end(), (vj = _1, _1 = vi, vi = vj));
About assignment and subscript operators As described in Section 5.2.2, Assignment and subscript operators , assignment and subscripting operators are always defined as member functions. This means, that for expressions of the form x = y or x[y] to be interpreted as lambda expressions, the lefthand operand x must be a lambda expression. Consequently, it is sometimes necessary to use var for this purpose. We repeat the example from Section 5.2.2, Assignment and subscript operators :
48
Chapter 4. Boost.Lambda
int i; i = _1; var(i) = _1; // error // ok
Note that the compound assignment operators +=, = etc. can be defined as nonmember functions, and thus they are interpreted as lambda expressions even if only the righthand operand is a lambda expression. Nevertheless, it is perfectly ok to delay the left operand explicitly. For example, i += _1 is equivalent to var(i) += _1.
The BLL supports the following function templates for control structures:
if_then(condition, then_part) if_then_else(condition, then_part, else_part) if_then_else_return(condition, then_part, else_part) while_loop(condition, body) while_loop(condition) // no body case do_while_loop(condition, body) do_while_loop(condition) // no body case for_loop(init, condition, increment, body) for_loop(init, condition, increment) // no body case switch_statement(...)
The return types of all control construct lambda functor is void, except for if_then_else_return, which wraps a call to the conditional operator
condition ? then_part : else_part
The return type rules for this operator are somewhat complex. Basically, if the branches have the same type, this type is the return type. If the type of the branches differ, one branch, say of type A, must be convertible to the other branch, say of type B. In this situation, the result type is B. Further, if the common type is an lvalue, the return type will be an lvalue too. Delayed variables tend to be commonplace in control structure lambda expressions. For instance, here we use the var function to turn the arguments of for_loop into lambda expressions. The effect of the code is to add 1 to each element of a twodimensional array:
int a[5][10]; int i; for_each(a, a+5, for_loop(var(i)=0, var(i)<10, ++var(i), _1[var(i)] += 1));
The BLL supports an alternative syntax for control expressions, suggested by Joel de Guzmann. By overloading the operator[] we can get a closer resemblance with the builtin control structures:
if_(condition)[then_part] if_(condition)[then_part].else_[else_part] while_(condition)[body] do_[body].while_(condition) for_(init, condition, increment)[body]
For example, using this syntax the if_then example above can be written as:
for_each(a.begin(), a.end(), if_(_1 % 2 == 0)[ cout << _1 ])
49
Chapter 4. Boost.Lambda
As more experience is gained, we may end up deprecating one or the other of these syntaces. 5.6.1. Switch statement The lambda expressions for switch control structures are more complex since the number of cases may vary. The general form of a switch lambda expression is:
switch_statement(condition, case_statement<label>(lambda expression), case_statement<label>(lambda expression), ... default_statement(lambda expression) )
The condition argument must be a lambda expression that creates a lambda functor with an integral return type. The different cases are created with the case_statement functions, and the optional default case with the default_statement function. The case labels are given as explicitly specified template arguments to case_statement functions and break statements are implicitly part of each case. For example, case_statement<1>(a), where a is some lambda functor, generates the code:
case 1: evaluate lambda functor a; break;
The switch_statement function is specialized for up to 9 case statements. As a concrete example, the following code iterates over some container v and ouptuts zero for each 0, one for each 1, and other: n for any other value n. Note that another lambda expression is sequenced after the switch_statement to output a line break after each element:
std::for_each(v.begin(), v.end(), ( switch_statement( _1, case_statement<0>(std::cout << constant("zero")), case_statement<1>(std::cout << constant("one")), default_statement(cout << constant("other: ") << _1) ), cout << constant("\n") ) );
5.7. Exceptions
The BLL provides lambda functors that throw and catch exceptions. Lambda functors for throwing exceptions are created with the unary function throw_exception. The argument to this function is the exception to be thrown, or a lambda functor which creates the exception to be thrown. A lambda functor for rethrowing exceptions is created with the nullary rethrow function. Lambda expressions for handling exceptions are somewhat more complex. The general form of a lambda expression for try catch blocks is as follows:
try_catch( lambda expression, catch_exception<type>(lambda expression), catch_exception<type>(lambda expression), ... catch_all(lambda expression) )
50
Chapter 4. Boost.Lambda
The first lambda expression is the try block. Each catch_exception defines a catch block where the explicitly specified template argument defines the type of the exception to catch. The lambda expression within the catch_exception defines the actions to take if the exception is caught. Note that the resulting exception handlers catch the exceptions as references, i.e., catch_exception<T>(...) results in the catch block:
catch(T& e) { ... }
The last catch block can alternatively be a call to catch_exception<type> or to catch_all, which is the lambda expression equivalent to catch(...). The Example 4.1, Throwing and handling exceptions in lambda expressions. demonstrates the use of the BLL exception handling tools. The first handler catches exceptions of type foo_exception. Note the use of _1 placeholder in the body of the handler. The second handler shows how to throw exceptions, and demonstrates the use of the exception placeholder_e. It is a special placeholder, which refers to the caught exception object within the handler body. Here we are handling an exception of type std::exception, which carries a string explaining the cause of the exception. This explanation can be queried with the zeroargument member function what. The expression bind(&std::exception::what, _e) creates the lambda function for making that call. Note that _e cannot be used outside of an exception handler lambda expression. The last line of the second handler constructs a new exception object and throws that with throw exception. Constructing and destructing objects within lambda expressions is explained in Section 5.8, Construction and destruction Finally, the third handler (catch_all) demonstrates rethrowing exceptions.
51
Chapter 4. Boost.Lambda
The new_ptr<int>() expression creates a function object that calls new int() when invoked, and wrapping that inside bind makes it a lambda functor. In the same way, the expression delete_ptr() creates a function object that invokes delete on its argument. Note that new_ptr<T>() can take arguments as well. They are passed directly to the constructor invocation and thus allow calls to constructors which take arguments. As an example of constructor calls in lambda expressions, the following code reads integers from two containers x and y, constructs pairs out of them and inserts them into a third container:
vector<pair<int, int> > v; transform(x.begin(), x.end(), y.begin(), back_inserter(v), bind(constructor<pair<int, int> >(), _1, _2));
Table 4.1, Construction and destruction related function objects. lists all the function objects related to creating and destroying objects, showing the expression to create and call the function object, and the effect of evaluating that expression.
Table 4.1. Construction and destruction related function objects. Function object call constructor<T>()(arg_list) destructor()(a) destructor()(pa) new_ptr<T>()(arg_list) new_array<T>()(sz) delete_ptr()(p) delete_array()(p) T(arg_list) a.~A(), where a is of type A pa>~A(), where pa is of type A* new T(arg_list) new T[sz] delete p delete p[] Wrapped expression
The last line makes the call foo(bar(i)); Note that the first argument in a bind expression, the target function, is no exception, and can thus be a bind expression too. The innermost lambda functor just has to return something that can be used as a target function: another lambda functor, function pointer, pointer to member function etc. For example, in the following code the innermost lambda functor makes a selection between two functions, and returns a pointer to one of them:
int add(int a, int b) { return a+b; } int mul(int a, int b) { return a*b; } int(*)(int, int) add_or_mul(bool x) { return x ? add : mul; }
52
Chapter 4. Boost.Lambda
bool condition; int i; int j; ... bind(bind(&add_or_mul, _1), _2, _3)(condition, i, j); 5.9.1.1. Unlambda
A nested bind expression may occur inadvertently, if the target function is a variable with a type that depends on a template parameter. Typically the target function could be a formal parameter of a function template. In such a case, the programmer may not know whether the target function is a lambda functor or not. Consider the following function template:
template<class F> int nested(const F& f) { int x; ... bind(f, _1)(x); ... }
Somewhere inside the function the formal parameter f is used as a target function in a bind expression. In order for this bind call to be valid, f must be a unary function. Suppose the following two calls to nested are made:
int foo(int); int bar(int, int); nested(&foo); nested(bind(bar, 1, _1));
Both are unary functions, or function objects, with appropriate argument and return types, but the latter will not compile. In the latter call, the bind expression inside nested will become:
bind(bind(bar, 1, _1), _1)
which is an error. The call to bar returns int, not a unary function or function object. In the example above, the intent of the bind expression in the nested function is to treat f as an ordinary function object, instead of a lambda functor. The BLL provides the function template unlambda to express this: a lambda functor wrapped inside unlambda is not a lambda functor anymore, and does not take part into the argument substitution process. Note that for all other argument types unlambda is an identity operation, except for making nonconst objects const. Using unlambda, the nested function is written as:
template<class F> int nested(const F& f) { int x; ... bind(unlambda(f), _1)(x); ... } 5.9.1.2. Protect
The protect function is related to unlambda. It is also used to prevent the argument substitution taking place, but whereas unlambda turns a lambda functor into an ordinary function object for good, protect does this temporarily, for just one evaluation round. For example:
53
Chapter 4. Boost.Lambda
int x = 1, y = 10; (_1 + protect(_1 + 2))(x)(y);
The first call substitutes x for the leftmost _1, and results in another lambda functor x + (_1 + 2), which after the call with y becomes x + (y + 2), and thus finally 13. Primary motivation for including protect into the library, was to allow nested STL algorithm invocations (Section 5.11, Nesting STL algorithm invocations ). 5.9.2. Rvalues as actual arguments to lambda functors Actual arguments to the lambda functors cannot be nonconst rvalues. This is due to a deliberate design decision: either we have this restriction, or there can be no sideeffects to the actual arguments. There are ways around this limitation. We repeat the example from section Section 4.3, About actual arguments to lambda functors and list the different solutions:
int i = 1; int j = 2; (_1 + _2)(i, j); // ok (_1 + _2)(1, 2); // error (!)
1. If the rvalue is of a class type, the return type of the function that creates the rvalue should be defined as const. Due to an unfortunate language restriction this does not work for builtin types, as builtin rvalues cannot be const qualified. 2. If the lambda function call is accessible, the make_const function can be used to constify the rvalue. E.g.:
(_1 + _2)(make_const(1), make_const(2)); // ok
Commonly the lambda function call site is inside a standard algorithm function template, preventing this solution to be used. 3. If neither of the above is possible, the lambda expression can be wrapped in a const_parameters function. It creates another type of lambda functor, which takes its arguments as const references. For example:
const_parameters(_1 + _2)(1, 2); // ok
Note that const_parameters makes all arguments const. Hence, in the case were one of the arguments is a nonconst rvalue, and another argument needs to be passed as a nonconst reference, this approach cannot be used. 4. If none of the above is possible, there is still one solution, which unfortunately can break const correctness. The solution is yet another lambda functor wrapper, which we have named break_const to alert the user of the potential dangers of this function. The break_const function creates a lambda functor that takes its arguments as const, and casts away constness prior to the call to the original wrapped lambda functor. For example:
int i; ... (_1 += _2)(i, 2); // error, 2 is a nonconst rvalue const_parameters(_1 += _2)(i, 2); // error, i becomes const break_const(_1 += _2)(i, 2); // ok, but dangerous
Note, that the results of break_const or const_parameters are not lambda functors, so they cannot be used as subexpressions of lambda expressions. For instance:
break_const(_1 + _2) + _3; // fails. const_parameters(_1 + _2) + _3; // fails.
However, this kind of code should never be necessary, since calls to sub lambda functors are made inside the BLL, and are not affected by the nonconst rvalue problem.
54
Chapter 4. Boost.Lambda
5.10.1. Cast expressions The BLL defines its counterparts for the four cast expressions static_cast, dynamic_cast, const_cast and reinterpret_cast. The BLL versions of the cast expressions have the prefix ll_. The type to cast to is given as an explicitly specified template argument, and the sole argument is the expression from which to perform the cast. If the argument is a lambda functor, the lambda functor is evaluated first. For example, the following code uses ll_dynamic_cast to count the number of derived instances in the container a:
class base {}; class derived : public base {}; vector<base*> a; ... int count = 0; for_each(a.begin(), a.end(), if_then(ll_dynamic_cast<derived*>(_1), ++var(count)));
5.10.2. Sizeof and typeid The BLL counterparts for these expressions are named ll_sizeof and ll_typeid. Both take one argument, which can be a lambda expression. The lambda functor created wraps the sizeof or typeid call, and when the lambda functor is called the wrapped operation is performed. For example:
vector<base*> a; ... for_each(a.begin(), a.end(), cout << bind(&type_info::name, ll_typeid(*_1)));
Here ll_typeid creates a lambda functor for calling typeid for each element. The result of a typeid call is an instance of the type_info class, and the bind expression creates a lambda functor for calling the name member function of that class.
The BLL versions of the STL algorithms are classes, which define the function call operator (or several overloaded ones) to call the corresponding function templates in the std namespace. All these structs are placed in the subnamespace boost::lambda:ll. Note that there is no easy way to express an overloaded member function call in a lambda expression. This limits the usefulness of nested STL algorithms, as for instance the begin function has more than one overloaded definitions in container templates. In general, something analogous to the pseudocode below cannot be written:
std::for_each(a.begin(), a.end(), bind(ll::for_each(), _1.begin(), _1.end(), protect(sum += _1)));
Some aid for common special cases can be provided though. The BLL defines two helper function object classes, call_begin and call_end, which wrap a call to the begin and, respectively, end functions of a container, and return the const_iterator type of the container. With these helper templates, the above code becomes:
std::for_each(a.begin(), a.end(),
55
Chapter 4. Boost.Lambda
bind(ll::for_each(), bind(call_begin(), _1), bind(call_end(), _1), protect(sum += _1)));
Now, one can add a specialization stating, that if the left hand argument is of type X, and the right hand one of type Y, the return type of all such binary arithmetic operators is Z:
namespace boost { namespace lambda { template<class Act> struct plain_return_type_2<arithmetic_action<Act>, X, Y> { typedef Z type; }; } }
Having this specialization defined, BLL is capable of correctly deducing the return type of the above two operators. Note, that the specializations must be in the same namespace, ::boost::lambda, with the primary template. For brevity, we do not show the namespace definitions in the examples below. It is possible to specialize on the level of an individual operator as well, in addition to providing a specialization for a group of operators. Say, we add a new arithmetic operator for argument types X and Y:
X operator*(const X&, const Y&);
56
Chapter 4. Boost.Lambda
Our first rule for all arithmetic operators specifies that the return type of this operator is Z, which obviously is not the case. Hence, we provide a new rule for the multiplication operator:
template<> struct plain_return_type_2<arithmetic_action<multiply_action>, X, Y> { typedef X type; };
The specializations can define arbitrary mappings from the argument types to the return type. Suppose we have some mathematical vector type, templated on the element type:
template <class T> class my_vector;
Suppose the addition operator is defined between any two my_vector instantiations, as long as the addition operator is defined between their element types. Furthermore, the element type of the resulting my_vector is the same as the result type of the addition between the element types. E.g., adding my_vector<int> and my_vector<double> results in my_vector<double>. The BLL has traits classes to perform the implicit builtin and standard type conversions between integral, floating point, and complex classes. Using BLL tools, the addition operator described above can be defined as:
template<class A, class B> my_vector<typename return_type_2<arithmetic_action<plus_action>, A, B>::type> operator+(const my_vector<A>& a, const my_vector<B>& b) { typedef typename return_type_2<arithmetic_action<plus_action>, A, B>::type res_type; return my_vector<res_type>(); }
To allow BLL to deduce the type of my_vector additions correctly, we can define:
template<class A, class B> class plain_return_type_2<arithmetic_action<plus_action>, my_vector<A>, my_vector<B> > { typedef typename return_type_2<arithmetic_action<plus_action>, A, B>::type res_type; public: typedef my_vector<res_type> type; };
Note, that we are reusing the existing specializations for the BLL return_type_2 template, which require that the argument types are references.
Table 4.2. Action types + * / % + & arithmetic_action<plus_action> arithmetic_action<minus_action> arithmetic_action<multiply_action> arithmetic_action<divide_action> arithmetic_action<remainder_action> unary_arithmetic_action<plus_action> unary_arithmetic_action<minus_action> bitwise_action<and_action>
57
Chapter 4. Boost.Lambda
| ~ ^ << >> && || ! < > <= >= == != += = *= /= %= &= =| ^= <<= >>= ++ ++ & * ,
bitwise_action<or_action> bitwise_action<not_action> bitwise_action<xor_action> bitwise_action<leftshift_action_no_stream> bitwise_action<rightshift_action_no_stream> logical_action<and_action> logical_action<or_action> logical_action<not_action> relational_action<less_action> relational_action<greater_action> relational_action<lessorequal_action> relational_action<greaterorequal_action> relational_action<equal_action> relational_action<notequal_action> arithmetic_assignment_action<plus_action> arithmetic_assignment_action<minus_action> arithmetic_assignment_action<multiply_action> arithmetic_assignment_action<divide_action> arithmetic_assignment_action<remainder_action> bitwise_assignment_action<and_action> bitwise_assignment_action<or_action> bitwise_assignment_action<xor_action> bitwise_assignment_action<leftshift_action> bitwise_assignment_action<rightshift_action> pre_increment_decrement_action<increment_action> pre_increment_decrement_action<decrement_action> post_increment_decrement_action<increment_action> post_increment_decrement_action<decrement_action> other_action<address_of_action> other_action<contents_of_action> other_action<comma_action>
58
Chapter 4. Boost.Lambda
7. Practical considerations
7.1. Performance
In theory, all overhead of using STL algorithms and lambda functors compared to hand written loops can be optimized away, just as the overhead from standard STL function objects and binders can. Depending on the compiler, this can also be true in practice. We ran two tests with the GCC 3.0.4 compiler on 1.5 GHz Intel Pentium 4. The optimization flag 03 was used. In the first test we compared lambda functors against explicitly written function objects. We used both of these styles to define unary functions which multiply the argument repeatedly by itself. We started with the identity function, going up to x5. The expressions were called inside a std::transform loop, reading the argument from one std::vector<int> and placing the result into another. The length of the vectors was 100 elements. The running times are listed in Table 4.3, Test 1CPU time of expressions with integer multiplication written as a lambda expression and as a traditional handcoded function object class. The running times are expressed in arbitrary units. . We can observe that there is no significant difference between the two approaches. In the second test we again used std::transform to perform an operation to each element in a 100element long vector. This time the element type of the vectors was double and we started with very simple arithmetic expressions and moved to more complex ones. The running times are listed in Table 4.4, Test 2CPU time of arithmetic expressions written as lambda expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional handcoded function object classes. Using BLL terminology, a and b are bound arguments in the expressions, and x is open. All variables were of types double. The running times are expressed in arbitrary units. . Here, we also included classic STL style unnamed functions into tests. We do not show these expressions, as they get rather complex. For example, the last expression in Table 4.4, Test 2CPU time of arithmetic expressions written as lambda expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional handcoded function object classes. Using BLL terminology, a and b are bound arguments in the expressions, and x is open. All variables were of types double. The running times are expressed in arbitrary units. written with classic STL tools contains 7 calls to compose2, 8 calls to bind1st and altogether 14 constructor invocations for creating multiplies, minus and plus objects. In this test the BLL expressions are a little slower (roughly 10% on average, less than 14% in all cases) than the corresponding handwritten function objects. The performance hit is a bit greater with classic STL expressions, up to 27% for the simplest expressios. The tests suggest that the BLL does not introduce a loss of performance compared to STL function objects. With a reasonable optimizing compiler, one should expect the performance characteristics be comparable to using classic STL. Moreover, with simple expressions the performance can be expected to be close to that of explicitly written function objects. Note however, that evaluating a lambda functor consist of a sequence of calls to small functions that are declared inline. If the compiler fails to actually expand these functions inline, the performance can suffer. The running time can more than double if this happens. Although the above tests do not include such an expression, we have experienced this for some seemingly simple expressions.
Table 4.3. Test 1CPU time of expressions with integer multiplication written as a lambda expression and as a traditional handcoded function object class. The running times are expressed in arbitrary units. CPU time of expressions with integer multiplication written as a lambda expression and as a traditional handcoded function object class. The running times are expressed in arbitrary units. expression x x*x x*x*x x*x*x*x x*x*x*x*x 240 340 770 1180 1950 lambda expression 230 350 760 1210 1910 handcoded function object
59
Chapter 4. Boost.Lambda
Table 4.4. Test 2CPU time of arithmetic expressions written as lambda expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional handcoded function object classes. Using BLL terminology, a and b are bound arguments in the expressions, and x is open. All variables were of types double. The running times are expressed in arbitrary units. CPU time of arithmetic expressions written as lambda expressions, as classic STL unnamed functions (using compose2, bind1st etc.) and as traditional handcoded function object classes. Using BLL terminology, a and b are bound arguments in the expressions, and x is open. All variables were of types double. The running times are expressed in arbitrary units. expression ax ax ax(a+x) (ax(a+x))(a+x) ((ax) (a+x))(bx (b+x))(ax (b+x))(bx (a+x)) lambda expression 330 350 470 620 1660 classic STL expression 370 370 500 670 1660 handcoded function object 290 310 420 600 1460
Some additional performance testing with an earlier version of the library is described [Jr00].
7.3. Portability
The BLL works with the following compilers, that is, the compilers are capable of compiling the test cases that are included with the BLL: GCC 3.0.4 KCC 4.0f with EDG 2.43.1 GCC 2.96 (fails with one test case, the exception_test.cpp results in an internal compiler error. ) 7.3.1. Test coverage The following list describes the test files included and the features that each file covers: bind_tests_simple.cpp : Bind expressions of different arities and types of target functions: function pointers, function objects and member functions. Function composition with bind expressions. bind_tests_simple_function_references.cpp : Repeats all tests from bind_tests_simple.cpp where the target function is a function pointer, but uses function references instead.
60
Chapter 4. Boost.Lambda
bind_tests_advanced.cpp : Contains tests for nested bind expressions, unlambda, protect, const_parameters and break_const. Tests passing lambda functors as actual arguments to other lambda functors, currying, and using the sig template to specify the return type of a function object. operator_tests_simple.cpp : Tests using all operators that are overloaded for lambda expressions, that is, unary and binary arithmetic, bitwise, comparison, logical, increment and decrement, compound, assignment, subscrict, address of, dereference, and comma operators. The streaming nature of shift operators is tested, as well as pointer arithmetic with plus and minus operators. member_pointer_test.cpp : The pointer to member operator is complex enough to warrant a separate test file. control_structures.cpp : Tests for the looping and if constructs. switch_construct.cpp : Includes tests for all supported arities of the switch statement, both with and without the default case. exception_test.cpp : Includes tests for throwing exceptions and for try/catch constructs with varying number of catch blocks. constructor_tests.cpp : Contains tests for constructor, destructor, new_ptr, delete_ptr, new_array and delete_array. cast_test.cpp : Tests for the four cast expressions, as well as typeid and sizeof. extending_return_type_traits.cpp : Tests extending the return type deduction system for user defined types. Contains several user defined operators and the corresponding specializations for the return type deduction templates. is_instance_of_test.cpp : Includes tests for an internally used traits template, which can detect whether a given type is an instance of a certain template or not. bll_and_function.cpp : Contains tests for using boost::function together with lambda functors.
The return and parameter types of the wrapped function object must be written explicilty as the template argument to the wrapper template boost::function; even when lambda functors, which otherwise have generic parameters, are wrapped. Wrapping a function object with boost::function introduces a performance cost comparable to virtual function dispatch, though virtual functions are not actually used. Note that storing lambda functors inside boost::function introduces a danger. Certain types of lambda functors may store references to the bound arguments, instead as taking copies of the arguments of the lambda expression. When temporary lambda functor objects are used in STL algorithm invocations this is always safe, as the lambda functor gets destructed immediately after the STL algortihm invocation is completed. However, a lambda functor wrapped inside boost::function may continue to exist longer, creating the possibility of dangling references. For example:
int* sum = new int(); *sum = 0; boost::function<int&(int)> counter = *sum += _1; counter(5); // ok, *sum = 5; delete sum; counter(3); // error, *sum does not exist anymore
61
Chapter 4. Boost.Lambda
To get this functionality in BLL, the bind expression inside the foo function can be written as:
bind(unlambda(f), _1)(x);
as explained in Section 5.9.1.1, Unlambda . The BB library supports up to nine placeholders, while the BLL defines only three placeholders. The rationale for not providing more, is that the highest arity of the function objects accepted by any STL algorithm is two. The placeholder count is easy to increase in the BB library. In BLL it is possible, but more laborous. The BLL currently passes the actual arguments to the lambda functors internally just as they are and does not wrap them inside a tuple object. The reason for this is that some widely used compilers are not capable of optimizing the intermediate tuple objects away. The creation of the intermediate tuples would cause a significant performance hit, particularly for the simplest (and thus the most common) lambda functors. We are working on a hybrid approach, which will allow more placeholders but not compromise the performance of simple lambda functors.
62
Chapter 4. Boost.Lambda
9. Contributors
The main body of the library was written by Jaakko Jrvi and Gary Powell. We've got outside help, suggestions and ideas from Jeremy Siek, Peter Higley, Peter Dimov, Valentin Bonnard, William Kempf. We would particularly like to mention Joel de Guzmann and his work with Phoenix which has influenced BLL significantly, making it considerably simpler to extend the library with new features.
This first line discards arguments x and y, and makes the call:
g(z, z, z)
In earlier versions of the library, the latter line resulted in a compile time error. This is basically a tradeoff between safety and flexibility, and the issue was extensively discussed during the Boost review period of the library. The main points for the strict arity checking was that it might catch a programming error at an earlier time and that a lambda expression that explicitly discards its arguments is easy to write:
(_3, bind(g, _1, _1, _1))(x, y, z);
This lambda expression takes three arguments. The lefthand argument of the comma operator does nothing, and as comma returns the result of evaluating the righthand argument we end up with the call g(x, x, x) even with the strict arity. The main points against the strict arity checking were that the need to discard arguments is commonplace, and should therefore be straightforward, and that strict arity checking does not really buy that much more safety, particularly as it is not symmetric. For example, if the programmer wanted to write the expression _1 + _2 but mistakenly wrote _1 + 2, with strict arity checking, the complier would spot the error. However, if the erroneous expression was 1 + _2 instead, the error would go unnoticed. Furthermore, weak arity checking simplifies the implementation a bit. Following the recommendation of the Boost review, strict arity checking was dropped.
Bibliography
[STL94] A. A. Stepanov and M. Lee. The Standard Template Library. HewlettPackard Laboratories. 1994. www.hpl.hp.com/techreports.
63
Chapter 4. Boost.Lambda
[Jr99] Jaakko Jrvi. C++ Function Object Binders Made Easy. . Lecture Notes in Computer Science. 1977. Springer. 2000.
[Jr00] Jaakko Jrvi. Gary Powell. The Lambda Library : Lambda Abstraction in C++. Turku Centre for Computer Science. Technical Report . 378. 2000. www.tucs.fi/publications.
[Jr01] Jaakko Jrvi. Gary Powell. The Lambda Library : Lambda Abstraction in C++. Second Workshop on C++ Template Programming. Tampa Bay, OOPSLA'01. . 2001. www.oonumerics.org/tmpw01/.
[Jr03] Jaakko Jrvi. Gary Powell. Andrew Lumsdaine. The Lambda Library : unnamed functions in C++. . Software Practice and Expreience. 33:259291. 2003.
[fc++] The FC++ library: Functional Programming in C++. Yannis Smaragdakis. Brian McNamara. www.cc.gatech.edu/~yannis/fc++/. 2002.
[1]
Strictly taken, the C++ standard defines for_each as a nonmodifying sequence operation, and the function object passed to for_each should not modify its argument. The requirements for the arguments of for_each are unnecessary strict, since as long as the iterators are mutable, for_each accepts a function object that can have sideeffects on their argument. Nevertheless, it is straightforward to provide another function template with the functionality ofstd::for_each but more finegrained requirements for its arguments.
64
Chapter 5. Boost.Program_options
Vladimir Prus Copyright 2002, 2003, 2004 Vladimir Prus
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. Introduction
The program_options library allows program developers to obtain program options, that is (name, value) pairs from the user, via conventional methods such as command line and config file. Why would you use such a library, and why is it better than parsing your command line by straightforward handwritten code? It's easier. The syntax for declaring options is simple, and the library itself is small. Things like conversion of option values to desired type and storing into program variables are handled automatically. Error reporting is better. All the problems with the command line are reported, while handwritten code can just misparse the input. In addition, the usage message can be automatically generated, to avoid falling out of sync with the real list of options. Options can be read from anywhere. Sooner or later the command line will be not enough for your users, and you'll want config files or maybe even environment variables. These can be added without significant effort on your part. Now let's see some examples of the library usage in the Section 2, Tutorial .
2. Tutorial
In this section, we'll take a look at the most common usage scenarios of the program_options library, starting with the simplest one. The examples show only the interesting code parts, but the complete programs can be found in the "BOOST_ROOT/libs/program_options/example" directory. Through all the examples, we'll assume that the following namespace alias is in effect:
namespace po = boost::program_options;
65
Chapter 5. Boost.Program_options
if (vm.count("compression")) { cout << "Compression level was set to " << vm["compression"].as<int>() << ".\n"; } else { cout << "Compression level was not set.\n"; }
We start by declaring all allowed options using the options_description class. The add_options method of that class returns a special proxy object that defines operator(). Calls to that operator actually declare options. The parameters are option name, information about value, and option description. In this example, the first option has no value, and the second one has a value of type int. After that, an object of class variables_map is declared. That class is intended to store values of options, and can store values of arbitrary types. Next, the calls to store, parse_command_line and notify functions cause vm to contain all the options found on the command line. And now, finally, we can use the options as we like. The variables_map class can be used just like std::map, except that values stored there must be retrieved with the as method shown above. (If the type specified in the call to the as method is different from the actually stored type, an exception is thrown.) It's now a good time to try compiling the code yourself, but if you're not yet ready, here's an example session:
$bin/gcc/debug/first Compression level was not set. $bin/gcc/debug/first help Allowed options: help : produce help message compression arg : set compression level $bin/gcc/debug/first compression 10 Compression level was set to 10.
The "help" option should be familiar from the previous example. It's a good idea to have this option in all cases. The "optimization" option shows two new features. First, we specify the address of the variable(&opt). After storing values, that variable will have the value of the option. Second, we specify a default value of 10, which will be used if no value is specified by the user. The "includepath" option is an example of the only case where the interface of the options_description class serves only one source the command line. Users typically like to use short option names for common options, and the "includepath,I" name specifies that short option name is "I". So, both "includepath" and "I" can be used.
66
Chapter 5. Boost.Program_options
The "inputfile" option specifies the list of files to process. That's okay for a start, but, of course, writing something like:
compiler inputfile=a.cpp
We'll address this in a moment. The command line tokens which have no option name, as above, are called "positional options" by this library. They can be handled too. With a little help from the user, the library can decide that "a.cpp" really means the same as "inputfile=a.cpp". Here's the additional code we need:
po::positional_options_description p; p.add("inputfile", 1); po::variables_map vm; po::store(po::command_line_parser(ac, av). options(desc).positional(p).run(), vm); po::notify(vm);
The first two lines say that all positional options should be translated into "inputfile" options. Also note that we use the command_line_parser class to parse the command line, not the parse_command_line function. The latter is a convenient wrapper for simple cases, but now we need to pass additional information. By now, all options are described and parsed. We'll save ourselves the trouble of implementing the rest of the compiler logic and only print the options:
if (vm.count("includepath")) { cout << "Include paths are: " << vm["includepath"].as< vector<string> >() << "\n"; } if (vm.count("inputfile")) { cout << "Input files are: " << vm["inputfile"].as< vector<string> >() << "\n"; } cout << "Optimization level is " << opt << "\n";
67
Chapter 5. Boost.Program_options
Oops, there's a slight problem. It's still possible to specify the "inputfile" option, and usage message says so, which can be confusing for the user. It would be nice to hide this information, but let's wait for the next example.
Note the call to the composing method in the declaration of the "includepath" option. It tells the library that values from different sources should be composed together, as we'll see shortly. The add method of the options_description class can be used to further group the options:
po::options_description cmdline_options; cmdline_options.add(generic).add(config).add(hidden); po::options_description config_file_options; config_file_options.add(config).add(hidden); po::options_description visible("Allowed options"); visible.add(generic).add(config);
68
Chapter 5. Boost.Program_options
The parsing and storing of values follows the usual pattern, except that we additionally call parse_config_file, and call the store function twice. But what happens if the same value is specified both on the command line and in config file? Usually, the value stored first is preferred. This is what happens for the "optimization" option. For "composing" options, like "includefile", the values are merged. Here's an example session:
$bin/gcc/debug/multiple_sources Include paths are: /opt Optimization level is 1 $bin/gcc/debug/multiple_sources help Allows options: Generic options: v [ version ] help
Configuration: optimization n : optimization level I [ includepath ] path : include path $bin/gcc/debug/multiple_sources optimization=4 I foo a.cpp b.cpp Include paths are: foo /opt Input files are: a.cpp b.cpp Optimization level is 4
The first invocation uses values from the configuration file. The second invocation also uses values from command line. As we see, the include paths on the command line and in the configuration file are merged, while optimization is taken from the command line.
3. Library Overview
In the tutorial section, we saw several examples of library usage. Here we will describe the overall library design including the primary components and their function. The library has three main components: The options description component, which describes the allowed options and what to do with the values of the options. The parsers component, which uses this information to find option names and values in the input sources and return them. The storage component, which provides the interface to access the value of an option. It also converts the string representation of values that parsers return into desired C++ types. To be a little more concrete, the options_description class is from the options description component, the parse_command_line function is from the parsers component, and the variables_map class is from the storage component. In the tutorial we've learned how those components can be used by the main function to parse the command line and config file. Before going into the details of each component, a few notes about the world outside of main. For that outside world, the storage component is the most important. It provides a class which stores all option values and that class can be freely passed around your program to modules which need access to the options. All the other components can be used only in the place where the actual parsing is the done. However, it might also make sense for the individual program modules to describe their options and pass them to the main module, which will merge all options. Of course, this is only important when the number of options is large and declaring them in one place becomes troublesome.
69
Chapter 5. Boost.Program_options
The call to the value function creates an instance of a class derived from the value_semantic class: typed_value. That class contains the code to parse values of a specific type, and contains a number of methods which can be called by the user to specify additional information. (This essentially emulates named parameters of the constructor.) Calls to operator() on the object returned by add_options forward arguments to the constructor of the option_description class and add the new instance. Note that in addition to the value, library provides the bool_switch function, and user can write his own function which will return other subclasses of value_semantic with different behaviour. For the remainder of this section, we'll talk only about the value function. The information about an option is divided into syntactic and semantic. Syntactic information includes the name of the option and the number of tokens which can be used to specify the value. This information is used by parsers to group tokens into (name, value) pairs, where value is just a vector of strings (std::vector<std::string>). The semantic layer is responsible for converting the value of the option into more usable C++ types. This separation is an important part of library design. The parsers use only the syntactic layer, which takes away some of the freedom to use overly complex structures. For example, it's not easy to parse syntax like:
calc expression=1 + 2/3
without knowing that it's a C expression. With a little help from the user the task becomes trivial, and the syntax clear:
calc expression="1 + 2/3"
3.1.1. Syntactic information The syntactic information is provided by the boost::program_options::options_description class and some methods of the boost::program_options::value_semantic class. The simplest usage is illustrated below:
options_description desc; desc.add_options() ("help", "produce help message") ;
This declares one option named "help" and associates a description with it. The user is not allowed to specify any value.
70
Chapter 5. Boost.Program_options
To make an option accept a value, you'd need the value function mentioned above:
options_description desc; desc.add_options() ("compression", "compression level", value<string>()) ("verbose", "verbosity level", value<string>()>implicit()) ("email", "email to send to", value<string>()>multitoken());
With these declarations, the user must specify a value for the first option, using a single token. For the second option, the user may either provide a single token for the value, or no token at all. For the last option, the value can span several tokens. For example, the following command line is OK:
test compression 10 verbose email beadle@mars beadle2@mars
3.1.2. Semantic information The semantic information is completely provided by the boost::program_options::value_semantic class. For example:
options_description desc; desc.add_options() ("compression", "compression level", value<int>()>default(10)); ("email", "email", value< vector<string> >() >composing()>notify(&your_function);
These declarations specify that default value of the first option is 10, that the second option can appear several times and all instances should be merged, and that after parsing is done, the library will call function &your_function, passing the value of the "email" option as argument. 3.1.3. Positional options Our definition of option as (name, value) pairs is simple and useful, but in one special case of the command line, there's a problem. A command line can include a positional option, which does not specify any name at all, for example:
archiver compression=9 /etc/passwd
Here, the "/etc/passwd" element does not have any option name. One solution is to ask the user to extract positional options himself and process them as he likes. However, there's a nicer approach provide a method to automatically assign the names for positional options, so that the above command line can be interpreted the same way as:
archiver compression=9 inputfile=/etc/passwd
The positional_options_description class allows the command line parser to assign the names. The class specifies how many positional options are allowed, and for each allowed option, specifies the name. For example:
positional_options_description pd; pd.add("inputfile", 1, 1);
specifies that for exactly one, first, positional option the name will be "inputfile". It's possible to specify that a number, or even all positional options, be given the same name.
positional_options_description pd; pd.add("outputfile", 2, 2).add_optional("inputfile", 0, 1);
71
Chapter 5. Boost.Program_options
In the above example, the first two positional options will be associated with name "outputfile", and any others with the name "inputfile".
The variables_map class is used to store the option values. The two calls to the store function add values found on the command line and in the config file. Finally the call to the notify function runs the userspecified notify functions and stores the values into regular variables, if needed. The priority is handled in a simple way: the store function will not change the value of an option if it's already assigned. In this case, if the command line specifies the value for an option, any value in the config file is ignored.
Warning
Don't forget to call the notify function after you've stored all parsed values.
72
Chapter 5. Boost.Program_options
4. How To
This section describes how the library can be used in specific situations.
For such cases, the library allows the user to provide an additional parser a function which will be called on each command line element, before any processing by the library. If the additional parser recognises the syntax, it returns the option name and value, which are used directly. The above example can be handled by the following code:
pair<string, string> reg_foo(const string& s) { if (s.find("f") == 0) { if (s.substr(2, 3) == "no") return make_pair(s.substr(5), string("false")); else return make_pair(s.substr(2), string("true")); } else { return make_pair(string(), string()); } }
Here's the definition of the additional parser. When parsing the command line, we pass the additional parser:
store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo) .run(), vm);
73
Chapter 5. Boost.Program_options
Second, you'll need an additional parser to support the standard syntax for specifying response files: "@file":
pair<string, string> at_option_parser(string const&s) { if ('@' == s[0]) return std::make_pair(string("responsefile"), s.substr(1)); else return pair<string, string>(); }
Finally, when the "responsefile" option is found, you'll have to load that file and pass it to the command line parser. This part is the hardest. We'll use the Boost.Tokenizer library, which works but has some limitations. You might also consider Boost.StringAlgo. The code is:
if (vm.count("responsefile")) { // Load the file and tokenize it ifstream ifs(vm["responsefile"].as<string>().c_str()); if (!ifs) { cout << "Could no open the response file\n"; return 1; } // Read the whole file into a string stringstream ss; ss << ifs.rdbuf(); // Split the file content char_separator<char> sep(" \n\r"); tokenizer<char_separator<char> > tok(ss.str(), sep); vector<string> args; copy(tok.begin(), tok.end(), back_inserter(args)); // Parse the file and store the options store(command_line_parser(args).options(desc).run(), vm); }
74
Chapter 5. Boost.Program_options
The function is an overload for wchar_t strings, so can also be used in Unicode applications.
After declaring options groups, we merge them in two combinations. The first will include all options and be used for parsing. The second will be used for the "help" option.
// Declare an options description instance which will include // all the options options_description all("Allowed options"); all.add(general).add(gui).add(backend); // Declare an options description instance which will be shown // to the user options_description visible("Allowed options"); visible.add(general).add(gui);
75
Chapter 5. Boost.Program_options
cout << backend; } else { cout << "Unknown module '" << s << "' in the helpmodule option\n"; return 1; } return 0; } if (vm.count("numthreads")) { cout << "The 'numthreads' options was set to " << vm["numthreads"].as<int>() << "\n"; }
When parsing the command line, all options are allowed. The "help" message, however, does not include the "Backend options" group the options in that group are hidden. The user can explicitly force the display of that options group by passing "helpmodule backend" option. The complete example can be found in the "example/option_groups.cpp" file.
The function takes four parameters. The first is the storage for the value, and in this case is either empty or contains an instance of the magic_number class. The second is the list of strings found in the next occurrence of the option. The remaining two parameters are needed to workaround the lack of partial template specialization and partial function template ordering on some compilers.
76
Chapter 5. Boost.Program_options
The function first checks that we don't try to assign to the same option twice. Then it checks that only a single string was passed in. Next the string is verified with the help of the Boost.Regex library. If that test is passed, the parsed value is stored into the v variable. The complete example can be found in the "example/regex.cpp" file.
which would set up the conversion facet according to the user's selected locale. It's wise to check the status of the C++ locale support on your implementation, though. The quick test involves three steps: 1. Go the the "test" directory and build the "test_convert" binary. 2. Set some nonascii locale in the environmemt. On Linux, one can run, for example:
$ export LC_CTYPE=ru_RU.KOI8R
3. Run the "test_convert" binary with any nonascii string in the selected encoding as its parameter. If you see a list of Unicode codepoints, everything's OK. Otherwise, locale support on your system might be broken.
5. Design Discussion
This section focuses on some of the design questions.
Chapter 5. Boost.Program_options
Generally, "Unicode support" can mean many things, but for the program_options library it means that: Each parser should accept either char* or wchar_t*, correctly split the input into option names and option values and return the data. For each option, it should be possible to specify whether the conversion from string to value uses ascii or Unicode. The library guarantees that: ascii input is passed to an ascii value without change Unicode input is passed to a Unicode value without change ascii input passed to a Unicode value, and Unicode input passed to an ascii value will be converted using a codecvt facet (which may be specified by the user(which can be specified by the user) The important point is that it's possible to have some "ascii options" together with "Unicode options". There are two reasons for this. First, for a given type you might not have the code to extract the value from Unicode string and it's not good to require that such code be written. Second, imagine a reusable library which has some options and exposes options description in its interface. If all options are either ascii or Unicode, and the library does not use any Unicode strings, then the author will likely to use ascii options, which would make the library unusable inside Unicode applications. Essentially, it would be necessary to provide two versions of the library ascii and Unicode. Another important point is that ascii strings are passed though without modification. In other words, it's not possible to just convert ascii to Unicode and process the Unicode further. The problem is that the default conversion mechanism the codecvt facet might not work with 8bit input without additional setup. The Unicode support outlined above is not complete. For example, we don't plan allow Unicode in option names. Unicode support is hard and requires a Boostwide solution. Even comparing two arbitrary Unicode strings is nontrivial. Finally, using Unicode in option names is related to internationalization, which has it's own complexities. E.g. if option names depend on current locale, then all program parts and other parts which use the name must be internationalized too. The primary question in implementing the Unicode support is whether to use templates and std::basic_string or to use some internal encoding and convert between internal and external encodings on the interface boundaries. The choice, mostly, is between code size and execution speed. A templated solution would either link library code into every application that uses the library (thereby making shared library impossible), or provide explicit instantiations in the shared library (increasing its size). The solution based on internal encoding would necessarily make conversions in a number of places and will be somewhat slower. Since speed is generally not an issue for this library, the second solution looks more attractive, but we'll take a closer look at individual components. For the parsers component, we have three choices: Use a fully templated implementation: given a string of a certain type, a parser will return a parsed_options instance with strings of the same type (i.e. the parsed_options class will be templated). Use internal encoding: same as above, but strings will be converted to and from the internal encoding. Use and partly expose the internal encoding: same as above, but the strings in the parsed_options instance will be in the internal encoding. This might avoid a conversion if parsed_options instance is passed directly to other components, but can be also dangerous or confusing for a user. The second solution appears to be the best it does not increase the code size much and is cleaner than the third. To avoid extra conversions, the Unicode version of parsed_options can also store strings in internal encoding. For the options descriptions component, we don't have much choice. Since it's not desirable to have either all options use ascii or all of them use Unicode, but rather have some ascii and some Unicode options, the interface of the value_semantic must work with both. The only way is to pass an additional flag telling if strings use ascii or internal encoding. The instance of value_semantic can then convert into some other encoding if needed. For the storage component, the only affected function is store. For Unicode input, the store function should convert the value to the internal encoding. It should also inform the value_semantic class about the used encoding.
78
Chapter 5. Boost.Program_options
Finally, what internal encoding should we use? The alternatives are: std::wstring (using UCS4 encoding) and std::string (using UTF8 encoding). The difference between alternatives is: Speed: UTF8 is a bit slower Space: UTF8 takes less space when input is ascii Code size: UTF8 requires additional conversion code. However, it allows one to use existing parsers without converting them to std::wstring and such conversion is likely to create a number of new instantiations. There's no clear leader, but the last point seems important, so UTF8 will be used. Choosing the UTF8 encoding allows the use of existing parsers, because 7bit ascii characters retain their values in UTF8, so searching for 7bit strings is simple. However, there are two subtle issues: We need to assume the character literals use ascii encoding and that inputs use Unicode encoding. A Unicode character (say '=') can be followed by 'composing character' and the combination is not the same as just '=', so a simple search for '=' might find the wrong character. Neither of these issues appear to be critical in practice, since ascii is almost universal encoding and since composing characters following '=' (and other characters with special meaning to the library) are not likely to appear.
6. Acknowledgements
I'm very gratefull to all the people who helped with the development, by discussion, fixes, and as users. It was pleasant to see all that involvement, which made the library much better than it would be otherwise. In the early stages, the library was affected by discussions with Gennadiy Rozental, William Kempf and Alexander Okhotin. Hartmut Kaiser was the first person to try the library on his project and send a number of suggestions and fixes. The formal review lead to numerous comments and enhancements. Pavol Droba helped with the option description semantic. Gennadiy Rozental has criticised many aspects of the library which caused various simplifications. Pavel Vozenilek did carefull review of the implementation. A number of comments were made by: David Abrahams Neal D. Becker Misha Bergal James Curran Carl Daniel Beman Dawes Tanton Gibbs Holger Grund Hartmut Kaiser Petr Kocmid Baptiste Lepilleur Marcelo E. Magallon Chuck Messenger John Torjo Matthias Troyer Doug Gregor and Reece Dunn helped to resolve the issues with Boostbook version of the documentation. Even after review, a number of people have helped with further development: Rob Lievaart Thorsten Ottosen Joseph Wu
79
Chapter 5. Boost.Program_options
Ferdinand Prantl Miro Jurisic John Maddock Janusz Piwowarski Charles Brockman Jonathan Wakely
7. Reference
7.1. Header <boost/program_options/cmdline.hpp>
namespace boost { namespace program_options { namespace command_line_style { enum style_t; } } }
enum style_t { allow_long = 1, allow_short = allow_long << 1, allow_dash_for_short = allow_short << 1, allow_slash_for_short = allow_dash_for_short << 1, long_allow_adjacent = allow_slash_for_sho short_allow_adjacent = long_allow_next << 1, short_allow_next = short_allow_adjacent << 1, a allow_guessing = allow_sticky << 1, case_insensitive = allow_guessing << 1, allow_long_disgu unix_style = (allow_short | short_allow_adjacent | short_allow_next | allow_long | long_allow_adjacent | long_allow_next | allow_sticky | allow_guessing | allow_dash_for_short), default_style = unix_style };
class environment_iterator : public boost::eof_iterator< environment_iterator, std::pair< std::string, std::s { public: // construct/copy/destruct environment_iterator(char **); environment_iterator(); // public member functions void get() ; };
80
Chapter 5. Boost.Program_options
Description
environment_iterator construct/copy/destruct
1. void get() ;
Description
The 'eof_iterator' class is useful for constructing forward iterators in cases where iterator extract data from some source and it's easy to detect 'eof' i.e. the situation where there's no data. One apparent example is reading lines from a file. Implementing such iterators using 'iterator_facade' directly would require to create class with three core operation, a couple of constructors. When using 'eof_iterator', the derived class should define only one method to get new value, plus a couple of constructors. The basic idea is that iterator has 'eof' bit. Two iterators are equal only if both have their 'eof' bits set. The 'get' method either obtains the new value or sets the 'eof' bit. Specifically, derived class should define: 1. A default constructor, which creates iterator with 'eof' bit set. The constructor body should call 'found_eof' method defined here. 2. Some other constructor. It should initialize some 'data pointer' used in iterator operation and then call 'get'. 3. The
81
Chapter 5. Boost.Program_options
'get' method. It should operate this way: look at some 'data pointer' to see if new element is available; if not, it should call 'found_eof'. extract new element and store it at location returned by the 'value' method. advance the data pointer. Essentially, the 'get' method has the functionality of both 'increment' and 'dereference'. It's very good for the cases where data extraction implicitly moves data pointer, like for stream operation.
eof_iterator construct/copy/destruct
1. eof_iterator();
eof_iterator public member functions
1. ValueType & value() ; Returns the reference which should be used by derived class to store the next value. 2. void found_eof() ; Should be called by derived class to indicate that it can't produce next element.
1. void increment() ; 2. bool equal(const eof_iterator & other) const; 3. const ValueType & dereference() const;
82
Chapter 5. Boost.Program_options
Synopsis class error { public: // construct/copy/destruct error(const std::string &); // public member functions };
Description
error construct/copy/destruct
Description
invalid_syntax construct/copy/destruct
83
Chapter 5. Boost.Program_options
Synopsis class unknown_option : public boost::program_options::error { public: // construct/copy/destruct unknown_option(const std::string &); // public member functions };
Description
unknown_option construct/copy/destruct
Description
ambiguous_option construct/copy/destruct
2. ~ambiguous_option();
ambiguous_option public member functions
84
Chapter 5. Boost.Program_options
Synopsis class multiple_values : public boost::program_options::error { public: // construct/copy/destruct multiple_values(const std::string &); // public member functions };
Description
Class thrown when there are several option values, but user called a method which cannot return them all.
multiple_values construct/copy/destruct
Description
Class thrown when there are several occurrences of an option, but user called a method which cannot return them all.
multiple_occurrences construct/copy/destruct
85
Chapter 5. Boost.Program_options
validation_error(const std::string &); ~validation_error(); // public member functions void set_option_name(const std::string &) ; // private member functions const char * what() const; };
Description
validation_error construct/copy/destruct
Description
invalid_option_value construct/copy/destruct
86
Chapter 5. Boost.Program_options
invalid_option_value public member functions
Description
too_many_positional_options_error construct/copy/destruct
Description
too_few_positional_options_error construct/copy/destruct
87
Chapter 5. Boost.Program_options
too_few_positional_options_error public member functions
Description
invalid_command_line_syntax construct/copy/destruct
Description
88
Chapter 5. Boost.Program_options
invalid_command_line_style construct/copy/destruct
Description
Option found in input source. Contains a key and a value. The key, in turn, can be a string (name of an option), or an integer (position in input source) in case no name is specified. The latter is only possible for command line. The template parameter specifies the type of char used for storing the option's value.
basic_option construct/copy/destruct
89
Chapter 5. Boost.Program_options
class options_description; class duplicate_option_error; } }
Description
Describes one possible command line/config file option. There are two kinds of properties of an option. First describe it syntactically and are used only to validate input. Second affect interpretation of the option, for example default value for it or function that should be called when the value is finally known. Routines which perform parsing never use second kind of properties they are side effect free. options_description
option_description construct/copy/destruct
1. option_description(); 2. option_description(const char * name, const value_semantic * s); Initializes the object with the passed data. Note: it would be nice to make the second parameter auto_ptr, to explicitly pass ownership. Unfortunately, it's often needed to create objects of types derived from 'value_semantic': options_description d; d.add_options()("a", parameter<int>("n")>default_value(1)); Here, the static type returned by 'parameter' should be derived from value_semantic. Alas, derived>base conversion for auto_ptr does not really work, see http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#84 So, we have to use plain old pointers. Besides, users are not expected to use the constructor directly.
90
Chapter 5. Boost.Program_options
The 'name' parameter is interpreted by the following rules: if there's no "," character in 'name', it specifies long name otherwise, the part before "," specifies long name and the part after long name. 3. option_description(const char * name, const value_semantic * s,
const char * description);
1. const std::string & short_name() const; 2. const std::string & long_name() const; 3. const std::string & description() const; 4. shared_ptr< const value_semantic > semantic() const; 5. std::string format_name() const; 6. std::string format_parameter() const; Return the parameter name and properties, formatted suitably for usage message.
Description
options_description_easy_init construct/copy/destruct
1. options_description_easy_init(options_description * owner);
91
Chapter 5. Boost.Program_options
options_description_easy_init public member functions
1. options_description_easy_init &
operator()(const char * name, const char * description) ;
2. options_description_easy_init &
operator()(const char * name, const value_semantic * s) ;
3. options_description_easy_init &
operator()(const char * name, const value_semantic * s, const char * description) ;
Description
A set of option descriptions. This provides convenient interface for adding new option (the add_options) method, and facilities to search for options by name. See here for option adding interface discussion. option_description
options_description construct/copy/destruct
1. options_description(); Creates the instance. 2. options_description(const std::string & caption); Creates the instance. The 'caption' parameter gives the name of this 'options_description' instance. Primarily useful for output.
92
Chapter 5. Boost.Program_options
options_description public member functions
1. void add(shared_ptr< option_description > desc) ; Adds new variable description. Throws duplicate_variable_error if either short or long name matches that of already present one. 2. options_description & add(const options_description & desc) ; Adds a group of option description. This has the same effect as adding all option_descriptions in 'desc' individually, except that output operator will show a separate group. Returns *this. 3. options_description_easy_init add_options() ; Returns an object of implementationdefined type suitable for adding options to options_description. The returned object will have overloaded operator() with parameter type matching 'option_description' constructors. Calling the operator will create new option_description instance and add it. 4. unsigned count(const std::string & name) const; Count the number of option descriptions with given name. Returns 0 or 1. The 'name' parameter can be either name of long option, and short option prefixed by ''. 5. unsigned count_approx(const std::string & prefix) const; Count the number of descriptions having the given string as prefix. This makes sense only for long options. 6. const option_description & find(const std::string & name) const; Returns description given a name. Requires count(name) == 1 7. const option_description & find_approx(const std::string & prefix) const; Returns description given a prefix. Throws Requires count_approx(name) == 1 8. std::set< std::string > keys() const; 9. std::set< std::string > primary_keys() const; For each option description stored, contains long name if not empty, if it is empty, short name is returned. 10. std::set< std::string > approximations(const std::string & prefix) const; 11. void print(std::ostream & os) const; Output 'desc' to the specified stream, calling 'f' to output each option_description element.
93
Chapter 5. Boost.Program_options
// public member functions };
Description
duplicate_option_error construct/copy/destruct
typedef basic_parsed_options< char > parsed_options; typedef basic_parsed_options< wchar_t > wparsed_options; typedef function1< std::pair< std::string, std::string >, const std::string & > ext_parser; typedef basic_command_line_parser< char > command_line_parser; typedef basic_command_line_parser< wchar_t > wcommand_line_parser; template<typename charT> basic_parsed_options< charT > parse_command_line(int, charT *, const options_description &, int = 0, function1< std::pair< std::string, std::string >, const std::string & > = ext_parser template<typename charT> BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options< charT > parse_config_file(std::basic_istream< charT > &, const options_description &); BOOST_PROGRAM_OPTIONS_DECL parsed_options parse_environment(const options_description &, const function1< std::string, std::string > &); BOOST_PROGRAM_OPTIONS_DECL parsed_options parse_environment(const options_description &, const std::string &); BOOST_PROGRAM_OPTIONS_DECL parsed_options parse_environment(const options_description &, const char *); } }
94
Chapter 5. Boost.Program_options
std::vector< basic_option< charT > > options; const options_description * description; };
Description
Results of parsing an input source. The primary use of this class is passing information from parsers component to value storage component. This class does not makes much sense itself.
basic_parsed_options construct/copy/destruct
Specializations
Class basic_parsed_options<wchar_t>
Description
Specialization of basic_parsed_options which: provides convenient conversion from basic_parsed_options<char> stores the passed charbased options for later use.
1. basic_parsed_options(const basic_parsed_options< char > & po) ; Constructs wrapped options from options in UTF8 encoding.
95
Chapter 5. Boost.Program_options
Description
common_command_line_parser construct/copy/destruct
1. parsed_options run() const; Parses the command line and returns parsed options in internal encoding.
Description
96
Chapter 5. Boost.Program_options
The class allows one to specify all the information needed for parsing and to parser the parse the command line. It is primarily needed to emulate named function parameters a regular function with 5 parameters will be hard to use and creating overloads with a smaller nuber of parameters will be confusing. For the most common case, the function parse_command_line is a better alternative.
basic_command_line_parser construct/copy/destruct
1. basic_command_line_parser(const std::vector< std::basic_string< charT > > & args); Creates a command line parser for the specified arguments list. The 'args' parameter should not include program name. 2. basic_command_line_parser(int argc, charT * argv); Creates a command line parser for the specified arguments list. The parameter should be the same as passes to 'main'.
1. basic_command_line_parser & options(const options_description & desc) ; Sets options descriptions to use. 2. basic_command_line_parser &
positional(const positional_options_description & desc) ;
Sets positional options description to use. 3. basic_command_line_parser & style(int ) ; Sets the command line style. 4. basic_command_line_parser & extra_parser(ext_parser ) ; Sets the extra parsers. 5. basic_parsed_options< charT > run() const; Parses the command line and returns parsed options in internal encoding.
template<typename charT> basic_parsed_options< charT > parse_command_line(int argc, charT * argv, const options_description & , int style = 0, function1< std::pair< std::string, std::string >, const std::string & > ext = ext_parser
Description
Creates instance of 'command_line_parser', passes parameters to it, and returns the result of calling the 'run' method.
97
Chapter 5. Boost.Program_options
Description
Description
Parse environment. For each environment variable, the 'name_mapper' function is called to obtain the option name. If it returns empty string, the variable is ignored. This is done since naming of environment variables is typically different from the naming of command line options.
Description
Parse environment. Takes all environment variables which start with 'prefix'. The option name is obtained from variable name by removing the prefix and converting the remaining string into lower case.
98
Chapter 5. Boost.Program_options
Description
Describes positional options. The class allows to guess option names for positional options, which are specified on the command line and are identified by the position. The class uses the information provided by the user to associate a name with every positional option, or tell that no name is known. The primary assumption is that only the relative order of the positional options themselves matters, and that any interleaving ordinary options don't affect interpretation of positional options. The user initializes the class by specifying that first N positional options should be given the name X1, following M options should be given the name X2 and so on.
positional_options_description construct/copy/destruct
1. positional_options_description();
positional_options_description public member functions
1. void add(const char * name, int max_count) ; Species that up to 'max_count' next positional options should be given the 'name'. The value of '1' means 'unlimited'. No calls to 'add' can be made after call with 'max_value' equal to '1'. 2. unsigned max_total_count() const; Returns the maximum number of positional options that can be present. Can return numeric_limits<unsigned>::max() to indicate unlimited number. 3. const std::string & name_for_position(unsigned position) const;
99
Chapter 5. Boost.Program_options
Returns the name that should be associated with positional options at 'position'. Precondition: position < max_total_count()
Description
Class which specifies how the option's value is to be parsed and converted into C++ types.
value_semantic construct/copy/destruct
1. ~value_semantic();
value_semantic public member functions
100
Chapter 5. Boost.Program_options
Returns the name of the option. The name is only meaningful for automatic help message. 2. virtual bool is_zero_tokens() const; Returns true if value cannot be specified in source at all. Other methods can still set the value somehow, but user can't affect it. 3. virtual bool is_composing() const; Returns true if values from different sources should be composed. Otherwise, value from the first source is used and values from other sources are discarded. 4. virtual bool is_implicit() const; Returns true if explicit value of an option can be omitted. 5. virtual bool is_multitoken() const; Returns true if value can span several token in input source. 6. virtual void
parse(boost::any & value_store, const std::vector< std::string > & new_tokens, bool utf8) const;
Parses a group of tokens that specify a value of option. Stores the result in 'value_store', using whatever representation is desired. May be be called several times if value of the same option is specified more than once. 7. virtual bool apply_default(boost::any & value_store) const; Called to assign default value to 'value_store'. Returns true if default value is assigned, and false if no default value exists. 8. virtual void notify(const boost::any & value_store) const; Called when final value of an option is determined.
Description
Helper class which perform necessary character conversions in the 'parse' method and forwards the data further.
Specializations
101
Chapter 5. Boost.Program_options
Synopsis class value_semantic_codecvt_helper<char> { public: // protected member functions virtual void xparse(boost::any &, const std::vector< std::string > &) const; // private member functions void parse(boost::any &, const std::vector< std::string > &, bool) const; };
Description
1. virtual void
xparse(boost::any & value_store, const std::vector< std::string > & new_tokens) const;
Description
1. virtual void
xparse(boost::any & value_store, const std::vector< std::wstring > & new_tokens) const;
102
Chapter 5. Boost.Program_options
Description
Class which specifies a simple handling of a value: the value will have string type and only one token is allowed.
untyped_value construct/copy/destruct
1. std::string name() const; 2. bool is_zero_tokens() const; 3. bool is_composing() const; 4. bool is_implicit() const; 5. bool is_multitoken() const; 6. void xparse(boost::any & value_store,
const std::vector< std::string > & new_tokens) const;
If 'value_store' is already initialized, or new_tokens has more than one elements, throws. Otherwise, assigns the first string from 'new_tokens' to 'value_store', without any modifications. 7. bool apply_default(boost::any & ) const; Does nothing. 8. void notify(const boost::any & ) const; Does nothing.
103
Chapter 5. Boost.Program_options
Synopsis template<typename T, typename charT = char> class typed_value : : public boost::program_options::value_semantic_codecvt_helper< charT > { public: // construct/copy/destruct typed_value(T *); // public member functions typed_value * default_value(const T &) ; typed_value * default_value(const T &, const std::string &) ; typed_value * notifier(function1< void, const T & >) ; typed_value * composing() ; typed_value * implicit() ; typed_value * multitoken() ; typed_value * zero_tokens() ; std::string name() const; bool is_zero_tokens() const; bool is_composing() const; bool is_implicit() const; bool is_multitoken() const; void xparse(boost::any &, const std::vector< std::basic_string< charT > > &) const; virtual bool apply_default(boost::any &) const; void notify(const boost::any &) const; };
Description
typed_value construct/copy/destruct
1. typed_value(T * store_to); Ctor. The 'store_to' parameter tells where to store the value when it's known. The parameter can be NULL.
1. typed_value * default_value(const T & v) ; Specifies default value, which will be used if none is explicitly specified. The type 'T' should provide operator<< for ostream. 2. typed_value * default_value(const T & v, const std::string & textual) ; Specifies default value, which will be used if none is explicitly specified. Unlike the above overload, the type 'T' need not provide operator<< for ostream, but textual representation of default value must be provided by the user. 3. typed_value * notifier(function1< void, const T & > f) ; Specifies a function to be called when the final value is determined. 4. typed_value * composing() ; Specifies that the value is composing. See the 'is_composing' method for explanation. 5. typed_value * implicit() ; Specifies that the value is implicit. 6. typed_value * multitoken() ; Specifies that the value can span multiple tokens.
104
Chapter 5. Boost.Program_options
7. typed_value * zero_tokens() ; 8. std::string name() const; 9. bool is_zero_tokens() const; 10. bool is_composing() const; 11. bool is_implicit() const; 12. bool is_multitoken() const; 13. void xparse(boost::any & value_store,
const std::vector< std::basic_string< charT > > & new_tokens) const;
Creates an instance of the 'validator' class and calls its operator() to perform athe ctual conversion. 14. virtual bool apply_default(boost::any & value_store) const; If default value was specified via previous call to 'default_value', stores that value into 'value_store'. Returns true if default value was stored. 15. void notify(const boost::any & value_store) const; If an address of variable to store value was specified when creating *this, stores the value there. Otherwise, does nothing.
Description
Creates a typed_value<T> instance. This function is the primary method to create value_semantic instance for a specific type, which can later be passed to 'option_description' constructor. The second overload is used when it's additionally desired to store the value of option into program variable.
Description
Creates a typed_value<T> instance. This function is the primary method to create value_semantic instance for a specific type, which can later be passed to 'option_description' constructor.
105
Chapter 5. Boost.Program_options
Synopsis BOOST_PROGRAM_OPTIONS_DECL typed_value< bool > * bool_switch(); BOOST_PROGRAM_OPTIONS_DECL typed_value< bool > * bool_switch(bool * v);
Description
Works the same way as the 'value<bool>' function, but the created value_semantic won't accept any explicit value. So, if the option is present on the command line, the value will be 'true'.
Description
Class holding value of option. Contains details about how the value is set and allows to conveniently obtain the value.
variable_value construct/copy/destruct
106
Chapter 5. Boost.Program_options
variable_value public member functions
1. template<typename T> const T & as() const; If stored value if of type T, returns that value. Otherwise, throws boost::bad_any_cast exception. 2. template<typename T> T & as() ; This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. 3. bool empty() const; 4. bool defaulted() const; Returns true if the value was not explicitly given, but has default value. 5. const boost::any & value() const; Returns the contained value. 6. boost::any & value() ; Returns the contained value.
Description
abstract_variables_map construct/copy/destruct
1. const variable_value & operator[](const std::string & name) const; Obtains the value of variable 'name', from *this and possibly from the chain of variable maps.
107
Chapter 5. Boost.Program_options
if there's no value in *this. if there's next variable map, returns value from it otherwise, returns empty value if there's defaulted value if there's next varaible map, which has a nondefauled value, return that otherwise, return value from *this if there's a nondefauled value, returns it. 2. void next(abstract_variables_map * next) ; Sets next variable map, which will be used to find variables not found in *this.
1. virtual const variable_value & get(const std::string & name) const; Returns value of variable 'name' stored in *this, or empty value otherwise.
Description
variables_map construct/copy/destruct
1. const variable_value & operator[](const std::string & name) const; Obtains the value of variable 'name', from *this and possibly from the chain of variable maps.
108
Chapter 5. Boost.Program_options
if there's no value in *this. if there's next variable map, returns value from it otherwise, returns empty value if there's defaulted value if there's next varaible map, which has a nondefauled value, return that otherwise, return value from *this if there's a nondefauled value, returns it.
1. const variable_value & get(const std::string & name) const; Implementation of abstract_variables_map::get which does 'find' in *this.
Description
Stores in 'm' all options that are defined in 'options'. If 'm' already has a nondefaulted value of an option, that value is not changed, even if 'options' specify some value.
Description
Stores in 'm' all options that are defined in 'options'. If 'm' already has a nondefaulted value of an option, that value is not changed, even if 'options' specify some value. This is wide character variant.
109
Chapter 5. Boost.Program_options
Synopsis BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map & m);
Description
Description
The version of the source interface. The value will be incremented whenever a change is made which might cause compilation errors for existing code.
110
Chapter 6. Boost.Ref
Jaakko Jrvi Peter Dimov Douglas Gregor Dave Abrahams Copyright 1999, 2000 Jaakko Jrvi Copyright 2001, 2002 Peter Dimov Copyright 2002 David Abrahams
Permission to copy, use, modify, sell and distribute this software is granted provided this copyright notice appears in all copies. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
1. Introduction
The Ref library is a small library that is useful for passing references to function templates (algorithms) that would usually take copies of their arguments. It defines the class template boost::reference_wrapper<T>, the two functions boost::ref and boost::cref that return instances of boost::reference_wrapper<T>, and the two traits classes boost::is_reference_wrapper<T> and boost::unwrap_reference<T>. The purpose of boost::reference_wrapper<T> is to contain a reference to an object of type T. It is primarily used to "feed" references to function templates (algorithms) that take their parameter by value. To support this usage, boost::reference_wrapper<T> provides an implicit conversion to T&. This usually allows the function templates to work on references unmodified. boost::reference_wrapper<T> is both CopyConstructible and Assignable (ordinary references are not Assignable). The expression boost::ref(x) returns a boost::reference_wrapper<X>(x) where X is the type of x. Similarly, boost::cref(x) returns a boost::reference_wrapper<X const>(x). The expression boost::is_reference_wrapper<T>::value is true if T is a reference_wrapper, and false otherwise. The typeexpression boost::unwrap_reference<T>::type is T::type if T is a reference_wrapper, T otherwise.
2. Reference
2.1. Header <boost/ref.hpp>
namespace boost { template<typename T> class reference_wrapper; reference_wrapper<T> ref(T&); reference_wrapper<T const> cref(T const&); template<typename T> class is_reference_wrapper; template<typename T> class unwrap_reference; }
111
Chapter 6. Boost.Ref
Description
reference_wrapper is primarily used to "feed" references to function templates (algorithms) that take their parameter by value. It provides an implicit conversion to T&, which usually allows the function templates to work on references unmodified.
reference_wrapper construct/copy/destruct
1. explicit reference_wrapper(T& t); Effects Constructs a reference_wrapper object that stores a reference to t. Throws Does not throw.
reference_wrapper access
1. operator T&() const; Returns The stored reference. Throws Does not throw. 2. T& get() const; Returns The stored reference. Throws Does not throw. 3. T* get_pointer() const; Returns A pointer to the object referenced by the stored reference.
112
Chapter 6. Boost.Ref
reference_wrapper constructors
1. reference_wrapper<T> ref(T& t); Returns reference_wrapper<T>(t) Throws Does not throw. 2. reference_wrapper<T const> cref(T const& t); Returns reference_wrapper<T const>(t) Throws Does not throw.
Description
The value static constant will be true iff the type T is a specialization of reference_wrapper.
Description
113
Chapter 6. Boost.Ref
3. Acknowledgements
ref and cref were originally part of the Tuple library by Jaakko Jrvi. They were "promoted to boost:: status" by Peter Dimov because they are generally useful. Douglas Gregor and Dave Abrahams contributed is_reference_wrapper and unwrap_reference.
114
Chapter 7. Boost.Signals
Douglas Gregor Copyright 2001, 2002, 2003, 2004 Douglas Gregor
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. Introduction
The Boost.Signals library is an implementation of a managed signals and slots system. Signals represent callbacks with multiple targets, and are also called publishers or events in similar systems. Signals are connected to some set of slots, which are callback receivers (also called event targets or subscribers), which are called when the signal is "emitted." Signals and slots are managed, in that signals and slots (or, more properly, objects that occur as part of the slots) track all connections and are capable of automatically disconnecting signal/slot connections when either is destroyed. This enables the user to make signal/slot connections without expending a great effort to manage the lifetimes of those connections with regard to the lifetimes of all objects involved. When signals are connected to multiple slots, there is a question regarding the relationship between the return values of the slots and the return value of the signals. Boost.Signals allows the user to specify the manner in which multiple return values are combined.
2. Tutorial
2.1. How to Read this Tutorial
This tutorial is not meant to be read linearly. Its toplevel structure roughly separates different concepts in the library (e.g., handling calling multiple slots, passing values to and from slots) and in each of these concepts the basic ideas are presented first and then more complex uses of the library are described later. Each of the sections is marked Beginner, Intermediate, or Advanced to help guide the reader. The Beginner sections include information that all library users should know; one can make good use of the Signals library after having read only the Beginner sections. The Intermediate sections build on the Beginner sections with slightly more complex uses of the library. Finally, the Advanced sections detail very advanced uses of the Signals library, that often require a solid working knowledge of the Beginner and Intermediate topics; most users will not need to read the Advanced sections.
Chapter 7. Boost.Signals
Comeau C++ 4.2.45.2 SGI MIPSpro 7.3.0 Intel C++ 5.0, 6.0 Compaq's cxx 6.2 Microsoft Visual C++ 7.1
Microsoft Visual C++ 6.0, 7.0 Borland C++ 5.5.1 Sun WorkShop 6 update 2 C++ 5.3 Metrowerks CodeWarrior 8.1
Portable syntax
struct HelloWorld { void operator()() const { std::cout << "Hello, World!" << std::endl; } }; // ... // Signal with no arguments and a void return value boost::signal0<void> sig; // Connect a HelloWorld slot HelloWorld hello; sig.connect(hello); // Call all of the slots sig();
The second slot will print ", World!" and a newline, to complete the program. The second slot may look like this:
struct World { void operator()() const { std::cout << ", World!" << std::endl; } };
116
Chapter 7. Boost.Signals
Like in our previous example, we can create a signal sig that takes no arguments and has a void return value. This time, we connect both a hello and a world slot to the same signal, and when we call the signal both slots will be called. Preferred syntax
boost::signal<void ()> sig; sig.connect(Hello()); sig.connect(World()); sig();
Portable syntax
boost::signal0<void> sig; sig.connect(Hello()); sig.connect(World()); sig();
By default, slots are called in firstin firstout (FIFO) order, so the output of this program will be as expected:
Hello, World!
2.4.2. Ordering slot call groups (Intermediate) Slots are free to have side effects, and that can mean that some slots will have to be called before others even if they are not connected in that order. The Boost.Signals library allows slots to be placed into groups that are ordered in some way. For our Hello, World program, we want "Hello" to be printed before ", World!", so we put "Hello" into a group that must be executed before the group that ", World!" is in. To do this, we can supply an extra parameter at the beginning of the connect call that specifies the group. Group values are, by default, ints, and are ordered by the integer < relation. Here's how we construct Hello, World: Preferred syntax
boost::signal<void ()> sig; sig.connect(1, World()); sig.connect(0, Hello()); sig();
Portable syntax
boost::signal0<void> sig; sig.connect(1, World()); sig.connect(0, Hello()); sig();
This program will correctly print "Hello, World!", because the Hello object is in group 0, which precedes group 1 where the World object resides. The group parameter is, in fact, optional. We omitted it in the first Hello, World example because it was unnecessary when all of the slots are independent. So what happens if we mix calls to connect that use the group parameter and those that don't? The "unnamed" slots (i.e., those that have been connected without specifying a group name) can be placed at the front or back of the slot list (by passing boost::signals::at_front or boost::signals::at_back as the last parameter to connect, respectively), and defaults to the end of the list. When a group is specified, the final parameter describes where the slot will be placed within the group ordering. If we add a new slot to our example like this:
struct GoodMorning { void operator()() const { std::cout << "... and good morning!" << std::endl; } }; sig.connect(GoodMorning());
117
Chapter 7. Boost.Signals
Preferred syntax
boost::signal<void (float, float)> sig; sig.connect(&print_sum); sig.connect(&print_product); sig.connect(&print_difference); sig.connect(&print_quotient); sig(5, 3);
Portable syntax
boost::signal2<void, float, float> sig; sig.connect(&print_sum); sig.connect(&print_product); sig.connect(&print_difference); sig.connect(&print_quotient); sig(5, 3);
So any values that are given to sig when it is called like a function are passed to each of the slots. We have to declare the types of these values up front when we create the signal. The type boost::signal<void (float, float)> means that the signal has a void return value and takes two float values. Any slot connected to sig must therefore be able to take two float values. 2.5.2. Signal Return Values (Advanced) Just as slots can receive arguments, they can also return values. These values can then be returned back to the caller of the signal through a combiner. The combiner is a mechanism that can take the results of calling slots (there many be no results or a hundred; we don't know until the program runs) and coalesces them into a single result to be returned to the caller. The single result is often a simple function of the results of the slot calls: the result of the last slot call, the maximum value returned by any slot, or a container of all of the results are some possibilities.
118
Chapter 7. Boost.Signals
We can modify our previous arithmetic operations example slightly so that the slots all return the results of computing the product, quotient, sum, or difference. Then the signal itself can return a value based on these results to be printed: Preferred syntax
float float float float product(float x, float y) { return x*y; } quotient(float x, float y) { return x/y; } sum(float x, float y) { return x+y; } difference(float x, float y) { return xy; }
Portable syntax
float float float float product(float x, float y) { return x*y; } quotient(float x, float y) { return x/y; } sum(float x, float y) { return x+y; } difference(float x, float y) { return xy; }
boost::signal<float (float x, float y)> sig; sig.connect(&product); sig.connect("ient); sig.connect(&sum); sig.connect(&difference); std::cout << sig(5, 3) << std::endl;
boost::signal2<float, float, float> sig; sig.connect(&product); sig.connect("ient); sig.connect(&sum); sig.connect(&difference); std::cout << sig(5, 3) << std::endl;
This example program will output 2. This is because the default behavior of a signal that has a return type (float, the first template argument given to the boost::signal class template) is to call all slots and then return the result returned by the last slot called. This behavior is admittedly silly for this example, because slots have no side effects and the result is the last slot connect. A more interesting signal result would be the maximum of the values returned by any slot. To do this, we create a custom combiner that looks like this:
template<typename T> struct maximum { typedef T result_type; template<typename InputIterator> T operator()(InputIterator first, InputIterator last) const { // If there are no slots to call, just return the // defaultconstructed value if (first == last) return T(); T max_value = *first++; while (first != last) { if (max_value < *first) max_value = *first; ++first; } return max_value; } };
The maximum class template acts as a function object. Its result type is given by its template parameter, and this is the type it expects to be computing the maximum based on (e.g., maximum<float> would find the maximum float in a sequence of floats). When a maximum object is invoked, it is given an input iterator sequence [first, last) that includes the results of calling all of the slots. maximum uses this input iterator sequence to calculate the maximum element, and returns that maximum value. We actually use this new function object type by installing it as a combiner for our signal. The combiner template argument follows the signal's calling signature: Preferred syntax Portable syntax
119
Chapter 7. Boost.Signals
boost::signal<float (float x, float y), maximum<float> > sig; boost::signal2<float, float, float, maximum<float> > sig;
Now we can connect slots that perform arithmetic functions and use the signal:
sig.connect("ient); sig.connect(&product); sig.connect(&sum); sig.connect(&difference); std::cout << sig(5, 3) << std::endl;
The output of this program will be 15, because regardless of the order in which the slots are connected, the product of 5 and 3 will be larger than the quotient, sum, or difference. In other cases we might want to return all of the values computed by the slots together, in one large data structure. This is easily done with a different combiner:
template<typename Container> struct aggregate_values { typedef Container result_type; template<typename InputIterator> Container operator()(InputIterator first, InputIterator last) const { return Container(first, last); } };
Again, we can create a signal with this new combiner: Preferred syntax
boost::signal<float (float, float), aggregate_values<std::vector<float> > > sig; sig.connect("ient); sig.connect(&product); sig.connect(&sum); sig.connect(&difference); std::vector<float> results = sig(5, 3); std::copy(results.begin(), results.end(), std::ostream_iterator<float>(cout, " "));
Portable syntax
boost::signal2<float, float, float, aggregate_values<std::vector<float> > > sig; sig.connect("ient); sig.connect(&product); sig.connect(&sum); sig.connect(&difference); std::vector<float> results = sig(5, 3); std::copy(results.begin(), results.end(), std::ostream_iterator<float>(cout, " "));
The output of this program will contain 15, 8, 1.6667, and 2. It is interesting here that the first template argument for the signal class, float, is not actually the return type of the signal. Instead, it is the return type used by the connected slots and will also be the value_type of the input iterators passed to the combiner. The combiner itself is a function object and its result_type member type becomes the return type of the signal. The input iterators passed to the combiner transform dereference operations into slot calls. Combiners therefore have the option to invoke only some slots until some particular criterion is met. For instance, in a distributed computing system, the combiner may ask each remote system whether it will handle the request. Only one remote system needs to handle a particular request, so after a remote system accepts the work we do not want to ask any other remote systems to perform the same task. Such a combiner need only check the value returned when dereferencing the iterator, and return when the value is acceptable. The following combiner returns the first nonNULL pointer to a FulfilledRequest data structure, without asking any later slots to fulfill the request:
struct DistributeRequest { typedef FulfilledRequest* result_type;
120
Chapter 7. Boost.Signals
template<typename InputIterator> result_type operator()(InputIterator first, InputIterator last) const { while (first != last) { if (result_type fulfilled = *first) return fulfilled; ++first; } return 0; } };
2.6.2. Scoped connections (Intermediate) The boost::signals::scoped_connection class references a signal/slot connection that will be disconnected when the scoped_connection class goes out of scope. This ability is useful when a connection need only be temporary, e.g.,
{ boost::signals::scoped_connection c = sig.connect(ShortLived()); sig(); // will call ShortLived function object } sig(); // ShortLived function object no longer connected to sig
2.6.3. Disconnecting equivalent slots (Intermediate) One can disconnect slots that are equivalent to a given function object using a form of the disconnect method, so long as the type of the function object has an accessible == operator. For instance: Preferred syntax
void foo(); void bar(); signal<void()> sig;
Portable syntax
void foo(); void bar(); signal0<void> sig;
121
Chapter 7. Boost.Signals
sig.connect(&foo); sig.connect(&bar); // disconnects foo, but not bar sig.disconnect(&foo); sig.connect(&foo); sig.connect(&bar); // disconnects foo, but not bar sig.disconnect(&foo);
2.6.4. Automatic connection management (Intermediate) Boost.Signals can automatically track the lifetime of objects involved in signal/slot connections, including automatic disconnection of slots when objects involved in the slot call are destroyed. For instance, consider a simple news delivery service, where clients connect to a news provider that then sends news to all connected clients as information arrives. The news delivery service may be constructed like this: Preferred syntax
class NewsItem { /* ... */ }; boost::signal<void (const NewsItem&)> deliverNews;
Portable syntax
class NewsItem { /* ... */ }; boost::signal1<void, const NewsItem&> deliverNews;
Clients that wish to receive news updates need only connect a function object that can receive news items to the deliverNews signal. For instance, we may have a special message area in our application specifically for news, e.g.,:
struct NewsMessageArea : public MessageArea { public: // ... void displayNews(const NewsItem& news) const { messageText = news.text(); update(); } }; // ... NewsMessageArea newsMessageArea = new NewsMessageArea(/* ... */); // ... deliverNews.connect(boost::bind(&NewsMessageArea::displayNews, newsMessageArea, _1));
However, what if the user closes the news message area, destroying the newsMessageArea object that deliverNews knows about? Most likely, a segmentation fault will occur. However, with Boost.Signals one need only make NewsMessageAreatrackable, and the slot involving newsMessageArea will be disconnected when newsMessageArea is destroyed. The NewsMessageArea class is made trackable by deriving publicly from the boost::signals::trackable class, e.g.:
struct NewsMessageArea : public MessageArea, public boost::signals::trackable { // ... };
At this time there is a significant limitation to the use of trackable objects in making slot connections: function objects built using Boost.Bind are understood, such that pointers or references to trackable objects passed to boost::bind will be found and tracked. Warning: Userdefined function objects and function objects from other libraries (e.g., Boost.Function or Boost.Lambda) do not implement the required interfaces for trackable object detection, and will silently ignore any bound trackable objects. Future versions of the Boost libraries will address this limitation.
122
Chapter 7. Boost.Signals
2.6.5. When can disconnections occur? (Intermediate) Signal/slot disconnections occur when any of these conditions occur: The connection is explicitly disconnected via the connection's disconnect method directly, or indirectly via the signal's disconnect method or scoped_connection's destructor. A trackable object bound to the slot is destroyed. The signal is destroyed. These events can occur at any time without disrupting a signal's calling sequence. If a signal/slot connection is disconnected at any time during a signal's calling sequence, the calling sequence will still continue but will not invoke the disconnected slot. Additionally, a signal may be destroyed while it is in a calling sequence, and which case it will complete its slot call sequence but may not be accessed directly. Signals may be invoked recursively (e.g., a signal A calls a slot B that invokes signal A...). The disconnection behavior does not change in the recursive case, except that the slot calling sequence includes slot calls for all nested invocations of the signal. 2.6.6. Passing slots (Intermediate) Slots in the Boost.Signals library are created from arbitrary function objects, and therefore have no fixed type. However, it is commonplace to require that slots be passed through interfaces that cannot be templates. Slots can be passed via the slot_type for each particular signal type and any function object compatible with the signature of the signal can be passed to a slot_type parameter. For instance: Preferred syntax
class Button { typedef boost::signal<void (int x, int y)> OnClick; public: void doOnClick(const OnClick::slot_type& slot); private: OnClick onClick; }; void Button::doOnClick( const OnClick::slot_type& slot ) { onClick.connect(slot); } void printCoordinates(long x, long y) { std::cout << "(" << x << ", " << y << ")\n"; } void f(Button& button) { button.doOnClick(&printCoordinates); }
Portable syntax
class Button { typedef boost::signal2<void,int,int> OnClick; public: void doOnClick(const OnClick::slot_type& slot); private: OnClick onClick; }; void Button::doOnClick( const OnClick::slot_type& slot ) { onClick.connect(slot); } void printCoordinates(long x, long y) { std::cout << "(" << x << ", " << y << ")\n"; } void f(Button& button) { button.doOnClick(&printCoordinates); }
The doOnClick method is now functionally equivalent to the connect method of the onClick signal, but the details of the doOnClick method can be hidden in an implementation detail file.
123
Chapter 7. Boost.Signals
3. Reference
3.1. Header <boost/signal.hpp>
namespace boost { template<typename typename typename typename class signalN; template<typename typename typename class signal; namespace signals R, typename T1, typename T2, ..., typename TN, Combiner = last_value<R>, typename Group = int, GroupCompare = std::less<Group>, SlotFunction = functionN<R, T1, T2, ..., TN> > Signature, typename Combiner = last_value<R>, Group = int, typename GroupCompare = std::less<Group>, SlotFunction = functionN<Signature> > {
124
Chapter 7. Boost.Signals
. . . typedef TN // static constants static const int arity = N; // construct/copy/destruct signalN(const combiner_type& = combiner_type(), const group_compare_type& = group_compare_type()); ~signalN(); // connection management signals::connection connect(const slot_type&, signals::connect_position = signals::at_back); signals::connection connect(const group_type&, const slot_type&, signals::connect_position = signals::at_back); void disconnect(const group_type&); template<typename Slot> void disconnect(const Slot&); void disconnect_all_slots(); bool empty() const; std::size_t num_slots() const; // invocation result_type operator()(arg1_type, arg2_type, ..., argN_type); result_type operator()(arg1_type, arg2_type, ..., argN_type) const; // combiner access combiner_type& combiner(); const combiner_type& combiner() const; };
argN_type;
Description
The class template signalN covers several related classes signal0, signal1, signal2, etc., where the number suffix describes the number of function parameters the signal and its connected slots will take. Instead of enumerating all classes, a single pattern signalN will be described, where N represents the number of function parameters.
signalN construct/copy/destruct
Effects Initializes the signal to contain no slots, copies the given combiner into internal storage, and stores the given group comparison function object to compare groups. Postconditions this>empty() 2. ~signalN(); Effects Disconnects all slots connected to *this.
1.
signals::connection connect(const slot_type& slot, signals::connect_position at = signals::at_back);
125
Chapter 7. Boost.Signals
signals::connection connect(const group_type& group, const slot_type& slot, signals::connect_position at = signals::at_back);
Effects Connects the signal this to the incoming slot. If the slot is inactive, i.e., any of the trackable objects bound by the slot call have been destroyed, then the call to connect is a noop. If the second version of connect is invoked, the slot is associated with the given group. The at parameter specifies where the slot should be connected: at_front indicates that the slot will be connected at the front of the list or group of slots and at_back indicates that the slot will be connected at the back of the list or group of slots. Returns A signals::connection object that references the newlycreated connection between the signal and the slot; if the slot is inactive, returns a disconnected connection. Throws This routine meets the strong exception guarantee, where any exception thrown will cause the slot to not be connected to the signal. Complexity Constant time when connecting a slot without a group name or logarithmic in the number of groups when connecting to a particular group. Notes It is unspecified whether connecting a slot while the signal is calling will result in the slot being called immediately. 2.
void disconnect(const group_type& group); template<typename Slot> void disconnect(const Slot& slot);
Effects If the parameter is (convertible to) a group name, any slots in the given group are disconnected. Otherwise, any slots equal to the given slot are disconnected. Throws Will not throw unless a user destructor or equality operator == throws. If either throws, not all slots may be disconnected. Complexity If a group is given, O(lg g) + k where g is the number of groups in the signal and k is the number of slots in the group. Otherwise, linear in the number of slots connected to the signal. 3. void disconnect_all_slots(); Effects Disconnects all slots connected to the signal. Postconditions this>empty(). Throws If disconnecting a slot causes an exception to be thrown, not all slots may be disconnected. Complexity Linear in the number of slots known to the signal. Notes May be called at any time within the lifetime of the signal, including during calls to the signal's slots. 4. bool empty() const; Returns true if no slots are connected to the signal, and false otherwise. Throws Will not throw. Complexity Linear in the number of slots known to the signal. Rationale Slots can disconnect at any point in time, including while those same slots are being invoked. It is therefore possible that the implementation must search through a list of disconnected slots to determine if any slots
126
Chapter 7. Boost.Signals
are still connected. 5. std::size_t num_slots() const; Returns The number of slots connected to the signal Throws Will not throw. Complexity Linear in the number of slots known to the signal. Rationale Slots can disconnect at any point in time, including while those same slots are being invoked. It is therefore possible that the implementation must search through a list of disconnected slots to determine how many slots are still connected.
signalN invocation
1.
result_type operator()(arg1_type a1, arg2_type a2, ... , argN_type aN); result_type operator()(arg1_type a1, arg2_type a2, ... , argN_type aN) const;
Effects Invokes the combiner with a slot_call_iterator range [first, last) corresponding to the sequence of calls to the slots connected to signal *this. Dereferencing an iterator in this range causes a slot call with the given set of parameters (a1, a2, ..., aN), the result of which is returned from the iterator dereference operation. Returns The result returned by the combiner. Throws If an exception is thrown by a slot call, or if the combiner does not dereference any slot past some given slot, all slots after that slot in the internal list of connected slots will not be invoked. Notes Only the slots associated with iterators that are actually dereferenced will be invoked. Multiple dereferences of the same iterator will not result in multiple slot invocations, because the return value of the slot will be cached. The const version of the function call operator will invoke the combiner as const, whereas the nonconst version will invoke the combiner as nonconst. Calling the function call operator may invoke undefined behavior if no slots are connected to the signal, depending on the combiner used. The default combiner is welldefined for zero slots when the return type is void but is undefined when the return type is any other type (because there is no way to synthesize a return value).
1.
combiner_type& combiner(); const combiner_type& combiner() const;
127
Chapter 7. Boost.Signals
Description
Class template signal is a thin wrapper around the numbered class templates signal0, signal1, etc. It accepts a function type with N arguments instead of N separate arguments, and derives from the appropriate signalN instantiation. All functionality of this class template is in its base class signalN.
signal construct/copy/destruct
Effects Initializes the base class with the given combiner and comparison objects.
Description
128
Chapter 7. Boost.Signals
slot construct/copy/destruct
1. template<typename Slot> slot(Slot target); Effects Invokes visit_each (unqualified) to discover pointers and references to signals::trackable objects in target. Initializes this to contain the incoming slot target, which may be any function object with which a SlotFunction can be constructed.
Description
The trackable class provides automatic disconnection of signals and slots when objects bound in slots (via pointer or reference) are destroyed. The trackable class may only be used as a public base class for some other class; when used as such, that class may be bound to function objects used as part of slots. The manner in which a trackable object tracks the set of signalslot connections it is a part of is unspecified. The actual use of trackable is contingent on the presence of appropriate visit_each overloads for any type that may contain pointers or references to trackable objects.
trackable construct/copy/destruct
1. trackable(); Effects Sets the list of connected slots to empty. Throws Will not throw. 2. trackable(const trackable& other); Effects Sets the list of connected slots to empty. Throws
129
Chapter 7. Boost.Signals
Will not throw. Rationale Signalslot connections can only be created via calls to an explicit connect method, and therefore cannot be created here when trackable objects are copied. 3. trackable& operator=(const trackable& other); Effects Sets the list of connected slots to empty. Returns *this Throws Will not throw. Rationale Signalslot connections can only be created via calls to an explicit connect method, and therefore cannot be created here when trackable objects are copied. 4. ~trackable(); Effects Disconnects all signal/slot connections that contain a pointer or reference to this trackable object that can be found by visit_each.
130
Chapter 7. Boost.Signals
Description
The connection class represents a connection between a Signal and a Slot. It is a lightweight object that has the ability to query whether the signal and slot are currently connected, and to disconnect the signal and slot. It is always safe to query or disconnect a connection.
connection construct/copy/destruct
1. connection(); Effects Sets the currently represented connection to the NULL connection. Postconditions !this>connected(). Throws Will not throw. 2. connection(const connection& other); Effects this references the connection referenced by other. Throws Will not throw. 3. connection& operator=(const connection& other); Effects this references the connection referenced by other. Throws Will not throw.
1. void disconnect() const; Effects If this>connected(), disconnects the signal and slot referenced by this; otherwise, this operation is a noop. Postconditions !this>connected(). 2. bool connected() const; Returns true if this references a nonNULL connection that is still active (connected), and false otherwise. Throws Will not throw.
connection modifiers
1. void swap(const connection& other); Effects Swaps the connections referenced in this and other. Throws Will not throw.
131
Chapter 7. Boost.Signals
connection comparisons
1. bool operator==(const connection& other) const; Returns true if this and other reference the same connection or both reference the NULL connection, and false otherwise. Throws Will not throw. 2. bool operator<(const connection& other) const; Returns true if the connection referenced by this precedes the connection referenced by other based on some unspecified ordering, and false otherwise. Throws Will not throw.
1. void swap(connection& x, connection& y); Effects x.swap(y) Throws Will not throw.
Description
scoped_connection construct/copy/destruct
1. scoped_connection(const connection& other); Effects this references the connection referenced by other. Throws Will not throw. 2. ~scoped_connection();
132
Chapter 7. Boost.Signals
1. void disconnect() const; Effects If this>connected(), disconnects the signal and slot referenced by this; otherwise, this operation is a noop. Postconditions !this>connected(). 2. bool connected() const; Returns true if this references a nonNULL connection that is still active (connected), and false otherwise. Throws Will not throw.
Description
The visit_each mechanism allows a visitor to be applied to every subobject in a given object. It is used by the Signals library to discover signals::trackable objects within a function object, but other uses may surface if used universally (e.g., conservative garbage collection). To fit within the visit_each framework, a visit_each overload must be supplied for each object type. Effects visitor(t), and for every subobject x of t: If x is a reference, visit_each(visitor, ref(x), 0) Otherwise, visit_each(visitor, x, 0) Notes The third parameter is long for the fallback version of visit_each and the argument supplied to this third paramter must always be 0. The third parameter is an artifact of the widespread lack of proper function template ordering, and will be removed in the future. Library authors will be expected to add additional overloads that specialize the T argument for their classes, so that subobjects can be visited.
133
Chapter 7. Boost.Signals
Evaluate an InputIterator sequence and return the last value in the sequence.
Description
last_value invocation
1. template<typename InputIterator>
result_type operator()(InputIterator first, InputIterator last) const;
Requires first != last Effects Dereferences every iterator in the sequence [first, last). Returns The result of dereferencing the iterator last1.
Specializations
Class last_value<void>
134
Chapter 7. Boost.Signals
// invocation template<typename InputIterator> result_type operator()(InputIterator, InputIterator) const; };
Description
last_value invocation
1. template<typename InputIterator>
result_type operator()(InputIterator first, InputIterator last) const;
5. Design Overview
5.1. Type Erasure
"Type erasure", where static type information is eliminated by the use of dynamically dispatched interfaces, is used extensively within the Boost.Signals library to reduce the amount of code generated by template instantiation. Each signal must manage a list of slots and their associated connections, along with a std::map to map from group identifiers to their associated connections. However, instantiating this map for every token type, and perhaps within each translation unit (for some popular template instantiation strategies) increase compile time overhead and space overhead. To combat this socalled "template bloat", we use Boost.Function and Boost.Any to store unknown types and operations. Then, all of the code for handling the list of slots and the mapping from slot identifiers to connections is factored into the class signal_base that deals exclusively with the any and function objects, hiding the actual implementations using the wellknown pimpl idiom. The actual signalN class templates deal only with code that will change depending on the number of arguments or which is inherently templatedependent (such as connection).
135
Chapter 7. Boost.Signals
Purpose An iterator through the list of slots connected to a signal. The value_type of this iterator will be std::pair<any, connection>, where the any contains an instance of the slot function type. This filtering iterator adaptor filters out slots that have been disconnected, so we never see a disconnected slot in later stages. The projection iterator adaptor returns a reference to the first member of the pair that constitutes a connected slot (e.g., just the boost::any object that holds the slot function). This transform iterator adaptor performs an any_cast to extract a reference to the slot function with the appropriate slot function type. This transform iterator adaptor calls the function object returned by dereferencing the underlying iterator with the set of arguments given to the signal itself, and returns the result of that slot call. This iterator adaptor caches the result of dereferencing the underlying iterator. Therefore, dereferencing this iterator multiple times will only result in the underlying iterator being dereferenced once; thus, a slot can only be called once but its result can be used multiple times. Iterates over calls to each slot.
136
Chapter 7. Boost.Signals
template<typename T> void foo(T, long); template<typename T> void foo(A<T>, int); A<T> at; foo(at, 0);
In this example, we assume that our compiler can not tell that A<T> is a better match than T, and therefore assume that the function templates cannot be ordered based on that parameter. Then the conversion from 0 to int is better than the conversion from 0 to long, and the second function template is chosen.
6. Design Rationale
6.1. Choice of Slot Definitions
The definition of a slot differs amongst signals and slots libraries. Within Boost.Signals, a slot is defined in a very loose manner: it can be any function object that is callable given parameters of the types specified by the signal, and whose return value is convertible to the result type expected by the signal. However, alternative definitions have associated pros and cons that were considered prior to the construction of Boost.Signals. Slots derive from a specific base class: generally a scheme such as this will require all userdefined slots to derive from some libraryspecified Slot abstract class that defines a virtual function calling the slot. Adaptors can be used to convert a definition such as this to a definition similar to that used by Boost.Signals, but the use of a large number of small adaptor classes containing virtual functions has been found to cause an unacceptable increase in the size of executables (polymorphic class types require more code than nonpolymorphic types). This approach does have the benefit of simplicity of implementation and user interface, from an objectoriented perspective. Slots constructed from a set of primitives: in this scheme the slot can have a limited set of types (often derived from a common abstract base class) that are constructed from some librarydefined set of primitives that often include conversions from free function pointers and member function pointers, and a limited set of binding capabilities. Such an approach is reasonably simple and cover most common cases, but it does not allow a large degree of flexibility in slot construction. Libraries for function object composition have become quite advanced and it is out of the scope of a signals and slots library to encorporate such enhancements. Thus Boost.Signals does not include argument binding or function object composition primitives, but instead provides a hook (via the visit_each mechanism) that allows existing binder/composition libraries to provide the necessary information to Signals. Users not satisfied with the slot definition choice may opt to replace the default slot function type with an alternative that meets their specific needs.
137
Chapter 7. Boost.Signals
Connections and disconnections must be paired, so the problem becomes similar to the problems incurred when pairing new and delete for dynamic memory allocation. While errors of this sort would not be catastrophic for a signals and slots implementation, their detection is generally nontrivial. Tokens must be unique, otherwise two slots will have the same name and will be indistinguishable. In environments where many connections will be made dynamically, name generation becomes an additional task for the user. Uniqueness of tokens also results in an additional failure mode when attempting to connect a slot using a token that has already been used. More parameterization would be required, because the token type must be userdefined. Additional parameterization steepens the learning curver and overcomplicates a simple interface. This type of interface is supported in Boost.Signals via the slot grouping mechanism. It augments the connection objectbased connection management scheme.
Push
struct push_max { typedef int result_type; push_max() : max_value(), got_first(false) {} // returns false when we want to stop bool operator()(int result) { if (result > 100) return false; if (!got_first) { got_first = true; max_value = result; return true; } if (result > max_value) max_value = result;
138
Chapter 7. Boost.Signals
private: int max_value; bool got_first; };
There are several points to note in these examples. The "pull" version is a reusable function object that is based on an input iterator sequence with an integer value_type, and is very straightforward in design. The "push" model, on the other hand, relies on an interface specific to the caller and is not generally reusable. It also requires extra state values to determine, for instance, if any elements have been received. Though code quality and easeofuse is generally subjective, the "pull" model is clearly shorter and more reusable and will often be construed as easier to write and understand, even outside the context of a signals & slots library. The cost of the "pull" combiner interface is paid in the implementation of the Signals library itself. To correctly handle slot disconnections during calls (e.g., when the dereference operator is invoked), one must construct the iterator to skip over disconnected slots. Additionally, the iterator must carry with it the set of arguments to pass to each slot (although a reference to a structure containing those arguments suffices), and must cache the result of calling the slot so that multiple dereferences don't result in multiple calls. This apparently requires a large degree of overhead, though if one considers the entire process of invoking slots one sees that the overhead is nearly equivalent to that in the "push" model, but we have inverted the control structures to make iteration and dereference complex (instead of making combiner statefinding complex).
139
Chapter 7. Boost.Signals
6.5.2. Why derivation from trackable? For trackable to work properly, there are two constraints: trackable must have storage space to keep track of all connections made to this object. trackable must be notified when the object is being destructed so that it can disconnect its connections. Clearly, deriving from trackable meets these two guidelines. We have not yet found a superior solution.
7. Testsuite
7.1. Acceptance tests
Test Type Description Ensure that calling connect with a slot that has already been disconnected via deletion does not actually connect to the slot. Test deletion of slots. Test slot group ordering. Basic test of signal/slot connections and invocation using the boost::signalN class templates. If failing...
140
Chapter 7. Boost.Signals
signal_test.cpp
run
Basic test of signal/slot connections and invocation using the boost::signal class template. Test automatic lifetime management using boost::trackable objects.
The boost::signal class template may not be usable on your compiler. However, the boost::signalN class templates may still be usable.
trackable_test.cpp
run
141
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. Introduction
The String Algorithm Library provides a generic implementation of stringrelated algorithms which are missing in STL. It is an extension to the algorithms library of STL and it includes trimming, case conversion, predicates and find/replace functions. All of them come in different variants so it is easier to choose the best fit for a particular need. The implementation is not restricted to work with a particular container (like std::basic_string), rather it is as generic as possible. This generalization is not compromising the performance since algorithms are using container specific features when it means a performance gain. Important note: In this documentation we use term string to designate a sequence of characters stored in an arbitrary container. A string is not restricted to std::basic_string and character does not have to be char or wchar_t, although these are most common candidates. Consult the design chapter to see precise specification of supported string types. The library interface functions and classes are defined in namespace boost::algorithm, and they are lifted into namespace boost via using declaration. The documentation is divided into several sections. For a quick start read the Usage section followed by Quick Reference. The Design Topics, Concepts and Rationale provide some explanation about the library design and structure an explain how it should be used. See the Reference for the complete list of provided utilities and algorithms. Functions and classes in the reference are organized by the headers in which they are defined. The reference contains links to the detailed description for every entity in the library.
2. Usage
2.1. First Example
Using the algorithms is straightforward. Let us have a look at the first example:
#include <boost/algorithm/string.hpp> using namespace std; using namespace boost; // ... string str1(" hello world! "); to_upper(str1); // str1 == " HELLO WORLD! " trim(str1); // str1 == "HELLO WORLD!" string str2= to_lower_copy( ireplace_first_copy( str1,"hello","goodbye")); // str2 == "goodbye world!"
142
This example converts str1 to upper case and trims spaces from the start and the end of the string. str2 is then created as a copy of str1 with "hello" replaced with "goodbye". This example demonstrates several important concepts used in the library: Container parameters: Unlike in the STL algorithms, parameters are not specified only in the form of iterators. The STL convention allows for great flexibility, but it has several limitations. It is not possible to stack algorithms together, because a container is passed in two parameters. Therefore it is not possible to use a return value from another algorithm. It is considerably easier to write to_lower(str1), than to_lower(str1.begin(), str1.end()). The magic of collection_traits provides a uniform way of handling different string types. If there is a need to pass a pair of iterators, iterator_range can be used to package iterators into a structure with a compatible interface. Copy vs. Mutable: Many algorithms in the library are performing a transformation of the input. The transformation can be done inplace, mutating the input sequence, or a copy of the transformed input can be created, leaving the input intact. None of these possibilities is superior to the other one and both have different advantages and disadvantages. For this reason, both are provided with the library. Algorithm stacking: Copy versions return a transformed input as a result, thus allow a simple chaining of transformations within one expression (i.e. one can write trim_copy(to_upper_copy(s))). Mutable versions have void return, to avoid misuse. Naming: Naming follows the conventions from the Standard C++ Library. If there is a copy and a mutable version of the same algorithm, the mutable version has no suffix and the copy version has the suffix _copy. Some algorithms have the prefix i (e.g. ifind_first()). This prefix identifies that the algorithm works in a caseinsensitive manner. To use the library, include the boost/algorithm/string.hpp header. If the regex related functions are needed, include the boost/algorithm/string_regex.hpp header.
to_upper() and to_lower() convert the case of characters in a string using a specified locale. For more information see the reference for boost/algorithm/string/case_conv.hpp.
str1("command.com"); str1 is_executable("command.com")? "is": "is not" "an executable" endl; // prints "command.com is an executable"
143
The predicates determine whether if a substring is contained in the input string under various conditions. The conditions are: a string starts with the substring, ends with the substring, simply contains the substring or if both strings are equal. See the reference for boost/algorithm/string/predicate.hpp for more details. In addition the algorithm all() checks all elements of a container to satisfy a condition specified by a predicate. This predicate can be any unary predicate, but the library provides a bunch of useful stringrelated predicates and combinators ready for use. These are located in the boost/algorithm/string/classification.hpp header. Classification predicates can be combined using logical combinators to form a more complex expressions. For example: is_from_range('a','z') || is_digit()
2.4. Trimming
When parsing the input from a user, strings usually have unwanted leading or trailing characters. To get rid of them, we need trim functions:
string str1=" hello world! "; string str2=trim_left_copy(str1); // str2 == "hello world! " string str3=trim_right_copy(str2); // str3 == " hello world!" trim(str1); // str1 == "hello world!" string phone="00423333444"; // remove leading 0 from the phone number trim_left_if(phone,is_any_of("0")); // phone == "423333444"
It is possible to trim the spaces on the right, on the left or on both sides of a string. And for those cases when there is a need to remove something else than blank space, there are _if variants. Using these, a user can specify a functor which will select the space to be removed. It is possible to use classification predicates like is_digit() mentioned in the previous paragraph. See the reference for the boost/algorithm/string/trim.hpp.
We have used find_last() to search the text for "ll". The result is given in the iterator_range. This range delimits the part of the input which satisfies the find criteria. In our example it is the last occurrence of "ll". As we can see, input of the find_last() algorithm can be also char[] because this type is supported by collection_traits. The following lines transform the result. Notice that iterator_range has familiar begin() and end() methods, so it can be used like any other STL container. Also it is convertible to bool therefore it is easy to use find algorithms for a simple containment checking.
144
// // // //
== == == ==
"Hello Jane, Hello World!" "Hello Jane, Goodbye World!" "HelloJane,GoodbyeWorld!" "Jane,GoodbyeWorld!"
For the complete list of replace and erase functions see the reference. There is a lot of predefined function for common usage, however, the library allows you to define a custom replace() that suits a specific need. There is a generic find_format() function which takes two parameters. The first one is a Finder object, the second one is a Formatter object. The Finder object is a functor which performs the searching for the replacement part. The Formatter object takes the result of the Finder (usually a reference to the found substring) and creates a substitute for it. Replace algorithm puts these two together and makes the desired substitution. Check boost/algorithm/string/replace.hpp, boost/algorithm/string/erase.hpp and boost/algorithm/string/find_format.hpp for reference.
typedef split_iterator<string::iterator> string_split_iterator; for(string_find_iterator It= make_split_iterator(str1, first_finder("*", is_iequal())); It!=string_find_iterator(); ++It) { cout << copy_iterator_range<std::string>(*It) << endl; } // Output will be: // abc // ABC
145
Note that the find iterators have only one template parameter. It is the base iterator type. The Finder is specified at runtime. This allows us to typedef a find iterator for common string types and reuse it. Additionally make_*_iterator functions help to construct a find iterator for a particular collection. See the reference in boost/algorithm/string/find_iterator.hpp.
2.8. Split
Split algorithms are an extension to the find iterator for one common usage scenario. These algorithms use a find iterator and store all matches into the provided container. This container must be able to hold copies (e.g. std::string) or references (e.g. iterator_range) of the extracted substrings. Two algorithms are provided. find_all() finds all copies of a string in the input. split() splits the input into parts.
string str1("hello abc*ABC*aBc goodbye"); typedef vector< iterator_range<string::iterator> > find_vector_type; find_vector_type FindVec; // #1: Search for separators ifind_all( FindVec, str1, "abc" ); // FindVec == { [abc],[ABC],[aBc] } typedef vector< string > split_vector_type; split_vector_type SplitVec; // #2: Search for tokens split( SplitVec, str1, is_any_of("*") ); // SplitVec == { "hello abc","ABC","aBc goodbye" }
[hello] designates an iterator_range delimiting this substring. First example show how to construct a container to hold references to all extracted substrings. Algorithm ifind_all() puts into FindVec references to all substrings that are in caseinsensitive manner equal to "abc". Second example uses split() to split string str1 into parts separated by characters '' or '*'. These parts are then put into the SplitVec. It is possible to specify if adjacent separators are concatenated or not. More information can be found in the reference: boost/algorithm/string/split.hpp.
3. Quick Reference
3.1. Algorithms
Table 8.1. Case Conversion Algorithm name to_upper to_lower Description Convert a string to upper case Convert a string to lower case Functions to_upper_copy() to_upper() to_lower_copy() to_lower()
146
Algorithm name
Description
Functions trim_left_copy_if() trim_left_if() trim_left_copy() trim_left() trim_right_copy_if() trim_right_if() trim_right_copy() trim_right() trim_copy_if() trim_if() trim_copy() trim()
trim_left
trim_right
trim
Table 8.3. Predicates Algorithm name starts_with ends_with contains equals all Description Check if a string is a prefix of the other one Check if a string is a suffix of the other one Check if a string is contained of the other one Check if two strings are equal Check if all elements of a string satisfy the given predicate Functions starts_with() istarts_with() ends_with() iends_with() contains() icontains() equals() iequals() all()
Table 8.4. Find algorithms Algorithm name find_first find_last find_nth find_head find_tail find_token find_regex Description Find the first occurrence of a string in the input Find the last occurrence of a string in the input Find the nth (zeroindexed) occurrence of a string in the input Retrieve the head of a string Retrieve the tail of a string Find first matching token in the string Use the regular expression to search the string Functions find_first() ifind_first() find_last() ifind_last() find_nth() ifind_nth() find_head() find_tail() find_token() find_regex()
147
find
find()
Table 8.5. Erase/Replace Algorithm name Description Functions replace_first() replace_first_copy() ireplace_first() ireplace_first_copy() erase_first() erase_first_copy() ierase_first() ierase_first_copy() replace_last() replace_last_copy() ireplace_last() ireplace_last_copy() erase_last() erase_last_copy() ierase_last() ierase_last_copy() replace_nth() replace_nth_copy() ireplace_nth() ireplace_nth_copy() erase_nth() erase_nth_copy() ierase_nth() ierase_nth_copy() replace_all() replace_all_copy() ireplace_all() ireplace_all_copy() erase_all() erase_all_copy() ierase_all() ierase_all_copy() replace_head() replace_head_copy() erase_head() erase_head_copy() replace_tail() replace_tail_copy() erase_tail() erase_tail_copy() replace_regex() replace_regex_copy() erase_regex() erase_regex_copy()
148
replace/erase_first
replace/erase_last
replace/erase_nth
replace/erase_all
replace/erase_head
replace/erase_tail
replace/erase_regex
find_format
Table 8.6. Split Algorithm name find_all Description Find/Extract all matching substrings in the input Functions find_all() ifind_all() find_all_regex() split() split_regex()
split
Table 8.8. Formatters Formatter const_formatter Description Constant formatter. Always return the specified string Generators const_formatter() identity_formatter() empty_formatter() regex_formatter()
identity_formatter Identity formatter. Return unmodified input input empty_formatter regex_formatter Null formatter. Always return an empty string
149
Regex formatter. Format regex match using the specification in the format string
3.3. Iterators
Table 8.9. Find Iterators Iterator name find_iterator split_iterator Description Iterates through matching substrings in the input Iterates through gaps between matching substrings in the input Iterator class find_iterator split_iterator
3.4. Classification
Table 8.10. Predicates Predicate name is_classified is_space is_alnum is_alpha is_cntrl is_digit is_graph is_lower is_print is_punct is_upper is_xdigit Description Generic ctype mask based classification Recognize spaces Recognize alphanumeric characters Recognize letters Recognize control characters Recognize decimal digits Recognize graphical characters Recognize lower case characters Recognize printable characters Recognize punctuation characters Recognize uppercase characters Recognize hexadecimal digits Generator is_classified() is_space() is_alnum() is_alpha() is_cntrl() is_digit() is_graph() is_lower() is_print() is_punct() is_upper() is_xdigit()
4. Design Topics
4.1. String Representation
As the name suggest, this library works mainly with strings. However, in the context of this library, a string is not restricted to any particular implementation (like std::basic_string), rather it is a concept. This allows the algorithms in this library to be reused for any string type, that satisfies the given requirements. Definition: A string is a collection of characters accessible in sequential ordered fashion. Character is any value type with "cheap" copying and assignment.
150
First requirement of stringtype is that it must accessible using collection traits. This facility allows to access the elements inside the string in a uniform iteratorbased fashion. This requirement is actually less stringent than that of collection concept. It implements an external collection interface. This is sufficient for our library Second requirement defines the way in which the characters are stored in the string. Algorithms in this library work with an assumption that copying a character is cheaper then allocating extra storage to cache results. This is a natural assumption for common character types. Algorithms will work even if this requirement is not satisfied, however at the cost of performance degradation. In addition some algorithms have additional requirements on the stringtype. Particularly, it is required that an algorithm can create a new string of the given type. In this case, it is required that the type satisfies the sequence (Std 23.1.1) requirements. In the reference and also in the code, requirement on the string type is designated by the name of template argument. CollectionT means that the basic collection requirements must hold. SequenceT designates extended sequence requirements.
Name value_type_of<C>::type
Description Type of contained values difference type of the collection iterator type of the collection const_iterator type of the collection result_iterator type of the collection. This type maps to C::iterator for mutable collection and C::const_iterator for const collection.
const_iterator_of<C>::type C::const_iterator result_iterator_of<C>::type begin(c) end(c) size(c) empty(c) c.begin() c.end() c.size() c.empty()
Gets the iterator pointing to the start of the collection. Gets the iterator pointing to the end of the collection. Gets the size of the collection. Checks if the collection is empty.
The collection traits are only a temporary part of this library. They will be replaced in the future releases by Boost.Range library. Use of the internal implementation will be deprecated then.
Table 8.12. Sequence Traits Trait has_native_replace<C>::value has_stable_iterators<C>::value Description Specifies that the sequence has std::string like replace method Specifies that the sequence has stable iterators. It means, that operations like insert/erase/replace do not invalidate iterators.
has_const_time_insert<C>::valueSpecifies that the insert method of the sequence has constant time complexity.
152
has_const_time_erase<C>::value Specifies that the erase method of the sequence has constant time complexity Current implementation contains specializations for std::list<T> and std::basic_string<T> from the standard library and SGI's std::rope<T> and std::slist<T>.
153
This guarantee can be provided under the condition that the operations on the types used for arguments for these functions either provide the strong exception guarantee or do not alter the global state . In the reference, under the term strong exceptionsafety guarantee, we mean the guarantee as defined above. For more information about the exception safety topics, follow this link
5. Concepts
5.1. Definitions
Table 8.13. Notation F Fmt Iter f fmt i,j A type that is a model of Finder A type that is a model of Formatter Iterator Type Object of type F Object of type Fmt Objects of type Iter
Table 8.14. Valid Expressions Expression Return Type f(i,j) Convertible to iterator_range<Iter> Effects Perform the search on the interval [i,j) and returns the result of the search
Various algorithms need to perform a search in a container and a Finder is a generalization of such search operations that allows algorithms to abstract from searching. For instance, generic replace algorithms can replace any part of the input, and the Finder is used to select the desired one. Note, that it is only required that the finder works with a particular iterator type. However, a Finder operation can be defined as a template, allowing the Finder to work with any iterator. Examples Finder implemented as a class. This Finder always returns the whole input as a match. operator() is templated, so that the finder can be used on any iterator type.
struct simple_finder { template<typename ForwardIteratorT> boost::iterator_range<ForwardIterator> operator()( ForwardIteratorT Begin, ForwardIteratorT End )
154
Function Finder. Finder can be any function object. That is, any ordinary function with the required signature can be used as well. However, such a function can be used only for a specific iterator type.
boost::iterator_range<std::string> simple_finder( std::string::const_iterator Begin, std::string::const_iterator End ) { return boost::make_range( Begin, End ); }
Table 8.15. Valid Expressions Expression fmt(f(i,j)) Return Type A container type, accessible using container traits Effects Formats the result of the finder operation
Similarly to finders, formatters generalize format operations. When a finder is used to select a part of the input, formatter takes this selection and performs some formating on it. Algorithms can abstract from formating using a formatter. Examples Formatter implemented as a class. This Formatter does not perform any formating and returns the match, repackaged. operator() is templated, so that the Formatter can be used on any Finder type.
struct simple_formatter { template<typename FindResultT> std::string operator()( const FindResultT& Match ) { std::string Temp( Match.begin(), Match.end() ); return Temp; } };
Function Formatter. Similarly to Finder, Formatter can be any function object. However, as a function, it can be used only with a specific Finder type.
std::string simple_formatter( boost::iterator_range<std::string::const_iterator>& Match ) { std::string Temp( Match.begin(), Match.end() ); return Temp; }
155
6. Reference
6.1. Header <boost/algorithm/string/case_conv.hpp>
Defines sequence caseconversion algorithms. Algorithms convert each element in the input sequence to the desired case using provided locales.
namespace boost { namespace algorithm { template<typename OutputIteratorT, typename CollectionT> OutputIteratorT to_lower_copy(OutputIteratorT, const CollectionT &, const std::locale & = std::locale()); template<typename SequenceT> SequenceT to_lower_copy(const SequenceT &, const std::locale & = std::locale()); template<typename MutableCollectionT> void to_lower(MutableCollectionT &, const std::locale & = std::locale()); template<typename OutputIteratorT, typename CollectionT> OutputIteratorT to_upper_copy(OutputIteratorT, const CollectionT &, const std::locale & = std::locale()); template<typename SequenceT> SequenceT to_upper_copy(const SequenceT &, const std::locale & = std::locale()); template<typename MutableCollectionT> void to_upper(MutableCollectionT &, const std::locale & = std::locale()); } }
Description
Each element of the input sequence is converted to lower case. The result is a copy of the input converted to lower case. It is returned as a sequence or copied to the output iterator. Parameters Input An input collection Loc A locale used for conversion Output An output iterator to which the result will be copied Returns
156
An output iterator pointing just after the last inserted character or a copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Each element of the input sequence is converted to lower case. The input sequence is modified inplace. Parameters Input A collection Loc a locale used for conversion
Description
Each element of the input sequence is converted to upper case. The result is a copy of the input converted to upper case. It is returned as a sequence or copied to the output iterator Parameters Input An input collection Loc A locale used for conversion Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a copy of the input
157
Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Each element of the input sequence is converted to upper case. The input sequence is modified inplace. Parameters Input An input collection Loc a locale used for conversion
158
is_classified predicate
Description
Construct the is_classified predicate. This predicate holds if the input is of specified std::ctype category. Parameters Loc A locale used for classification Type A std::ctype category Returns An instance of the is_classified predicate
is_space predicate
Description
Construct the is_classified predicate for the ctype_base::space category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_alnum predicate
159
Construct the is_classified predicate for the ctype_base::alnum category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_alpha predicate
Description
Construct the is_classified predicate for the ctype_base::alpha category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_cntrl predicate
Description
Construct the is_classified predicate for the ctype_base::cntrl category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
160
is_digit predicate
Description
Construct the is_classified predicate for the ctype_base::digit category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_graph predicate
Description
Construct the is_classified predicate for the ctype_base::graph category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_lower predicate
Description
is_print predicate
Description
Construct the is_classified predicate for the ctype_base::print category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_punct predicate
Description
Construct the is_classified predicate for the ctype_base::punct category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
162
Description
Construct the is_classified predicate for the ctype_base::upper category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_xdigit predicate
Description
Construct the is_classified predicate for the ctype_base::xdigit category. Parameters Loc A locale used for classification Returns An instance of the is_classified predicate
is_any_of predicate
Description
Construct the is_any_of predicate. The predicate holds if the input is included in the specified set of characters. Parameters Set A set of characters to be recognized
163
is_from_range predicate
Description
Construct the is_from_range predicate. The predicate holds if the input is included in the specified range. (i.e. From <= Ch <= To ) Parameters From The start of the range To The end of the range Returns An instance of the is_from_range predicate
Description
Construct the class_and predicate. This predicate can be used to logically combine two classification predicates. class_and holds, if both predicates return true. Parameters Pred1 The first predicate Pred2 The second predicate Returns An instance of the class_and predicate
164
Description
Construct the class_or predicate. This predicate can be used to logically combine two classification predicates. class_or holds, if one of the predicates return true. Parameters Pred1 The first predicate Pred2 The second predicate Returns An instance of the class_or predicate
Description
Construct the class_not predicate. This predicate represents a negation. class_or holds if of the predicates return false. Parameters Pred The predicate to be negated Returns An instance of the class_not predicate
165
collection_traits class
// // // // // // //
Function type. Value type. Size type. Iterator type. Const iterator type. Result iterator type ( iterator of cons Difference type.
Description
Collection traits provide uniform access to different types of collections. This functionality allows to write generic algorithms which work with several different kinds of collections. Currently following collection types are supported: containers with STL compatible container interface ( see ContainerConcept ) ( i.e. std::vector<> , std::list<> , std::string<> ... ) cstyle array ( char [10], int [15] ... ) nullterminated cstrings ( char* , wchar_T* ) std::pair of iterators ( i.e std::pair<vector<int>::iterator ,vector<int>::iterator> ) Collection traits provide an external collection interface operations. All are accessible using freestanding functions. The following operations are supported: size() empty() begin() end() Container traits have somewhat limited functionality on compilers not supporting partial template specialization and partial template ordering.
166
Description
Description
Description
167
Description
Container result_iterator.
Description
Extract the container's result_iterator type. This type maps to C::iterator for mutable container and C::const_iterator for const containers.
Description
Description
168
Description
Description
is_equal functor
Description
Standard STL equal_to only handle comparison between arguments of the same type. This is a less restrictive version which wraps operator ==.
169
Description
is_iequal construct/copy/destruct
1. is_iequal(const std::locale & Loc = std::locale()); Parameters Loc locales used for comparison
170
Finder concept.
Description
Defines the Finder concept. Finder is a functor which selects an arbitrary part of a string. Search is performed on the range specified by starting and ending iterators. Result of the find operation must be convertible to iterator_range.
Formatter concept.
Description
Defines the Formatter concept. Formatter is a functor, which takes a result from a finder operation and transforms it in a specific way. Result must be a container supported by container_traits, or a reference to it.
1. void constraints() ;
171
172
173
template<typename OutputIteratorT, typename CollectionT> OutputIteratorT erase_range_copy(OutputIteratorT Output, const CollectionT & Input, const iterator_range< typename const_iterator_of< CollectionT >::type > & SearchRange); template<typename SequenceT> SequenceT erase_range_copy(const SequenceT & Input, const iterator_range< typename const_iterator_of< SequenceT >::type > & SearchR
Description
Remove the given range from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input sequence Output An output iterator to which the result will be copied SearchRange A range in the input to be removed Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the given range from the input. The input sequence is modified inplace. Parameters Input An input sequence SearchRange A range in the input to be removed
174
Description
Remove the first occurence of the substring from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input string Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the first occurence of the substring from the input. The input sequence is modified inplace. Parameters Input An input string Search A substring to be searched for.
175
Description
Remove the first occurence of the substring from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the first occurence of the substring from the input. The input sequence is modified inplace. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Search
176
Description
Remove the last occurence of the substring from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input string Output An output iterator to which the result will be copied Search A substring to be searched for. Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the last occurence of the substring from the input. The input sequence is modified inplace. Parameters Input An input string Search A substring to be searched for
177
Description
Remove the last occurence of the substring from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the last occurence of the substring from the input. The input sequence is modified inplace. Searching is case insensitive. Parameters Input
178
An input string Loc A locale used for case insensitive comparison Search A substring to be searched for
Description
Remove the Nth occurence of the substring in the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input string Nth An index of the match to be replaced. The index is 0based. Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
179
Remove the Nth occurence of the substring in the input. The input sequence is modified inplace. Parameters Input An input string Nth An index of the match to be replaced. The index is 0based. Search A substring to be searched for.
Description
Remove the Nth occurence of the substring in the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Nth An index of the match to be replaced. The index is 0based. Output An output iterator to which the result will be copied Search A substring to be searched for. Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
180
Description
Remove the Nth occurence of the substring in the input. The input sequence is modified inplace. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Nth An index of the match to be replaced. The index is 0based. Search A substring to be searched for.
Description
Remove all the occurrences of the string from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input sequence Output An output iterator to which the result will be copied Search A substring to be searched for. Returns
181
An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove all the occurrences of the string from the input. The input sequence is modified inplace. Parameters Input An input string Search A substring to be searched for.
Description
Remove all the occurrences of the string from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search
182
A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove all the occurrences of the string from the input. The input sequence is modified inplace. Searching is case insensitive. Parameters Input An input string Loc A locale used for case insensitive comparison Search A substring to be searched for.
Description
Remove the head from the input. The head is a prefix of a seqence of given size. If the sequence is shorter then required, the whole string is considered to be the head. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input string N
183
Length of the head Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the head from the input. The head is a prefix of a seqence of given size. If the sequence is shorter then required, the whole string is considered to be the head. The input sequence is modified inplace. Parameters Input An input string N Length of the head
Description
Remove the tail from the input. The tail is a suffix of a seqence of given size. If the sequence is shorter then required, the whole string is considered to be the tail. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Input An input string N
184
Length of the head Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove the tail from the input. The tail is a suffix of a seqence of given size. If the sequence is shorter then required, the whole string is considered to be the tail. The input sequence is modified inplace. Parameters Input An input string N Length of the head
185
Description
Search the input using the given finder. Parameters Finder Finder object used for searching. Input A string which will be searched. Returns An iterator_range delimiting the match. Returned iterator is either CollectionT::iterator or CollectionT::const_iterator , depending on the constness of the input parameter.
Description
Search for the first occurence of the substring in the input. Parameters Input
186
A string which will be searched. Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either CollectionT::iterator or CollectionT::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
Description
Search for the first occurence of the substring in the input. Searching is case insensitive. Parameters Input A string which will be searched. Loc A locale used for case insensitive comparison Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
Description
187
Parameters Input A string which will be searched. Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
Description
Search for the last match a string in the input. Searching is case insensitive. Parameters Input A string which will be searched. Loc A locale used for case insensitive comparison Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
188
Search for the nth (zeroindexed) occurence of the substring in the input. Parameters Input A string which will be searched. Nth An index (zeroindexed) of the match to be found. Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter.
Description
Search for the nth (zeroindexed) occurence of the substring in the input. Searching is case insensitive. Parameters Input A string which will be searched. Loc A locale used for case insensitive comparison Nth An index (zeroindexed) of the match to be found. Search A substring to be searched for. Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
189
Description
Get the head of the input. Head is a prefix of the string of the given size. If the input is shorter then required, whole input if considered to be the head. Parameters Input An input string N Length of the head Returns An iterator_range delimiting the match. Returned iterator is either Collection1T::iterator or Collection1T::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
Description
Get the head of the input. Head is a suffix of the string of the given size. If the input is shorter then required, whole input if considered to be the tail. Parameters Input An input string N Length of the tail Returns An iterator_range delimiting the match. Returned iterator is either CollectionT::iterator or CollectionT::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
190
Description
Look for a given token in the string. Token is a character that matches the given predicate. If the "token compress mode" is enabled, adjacent tokens are considered to be one match. Parameters Input A input string. Pred An unary predicate to identify a token eCompress Enable/Disable compressing of adjacent tokens Returns An iterator_range delimiting the match. Returned iterator is either CollectionT::iterator or CollectionT::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
191
Description
Use the Finder to search for a substring. Use the Formatter to format this substring and replace it in the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Finder A Finder object used to search for a match to be replaced Formatter A Formatter object used to format a match Input An input sequence Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Use the Finder to search for a substring. Use the Formatter to format this substring and replace it in the input. The input is modified inplace. Parameters
192
Finder A Finder object used to search for a match to be replaced Formatter A Formatter object used to format a match Input An input sequence
Description
Use the Finder to search for a substring. Use the Formatter to format this substring and replace it in the input. Repeat this for all matching substrings. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Finder A Finder object used to search for a match to be replaced Formatter A Formatter object used to format a match Input An input sequence Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
193
Use the Finder to search for a substring. Use the Formatter to format this substring and replace it in the input. Repeat this for all matching substrings.The input is modified inplace. Parameters Finder A Finder object used to search for a match to be replaced Formatter A Formatter object used to format a match Input An input sequence
"Regex" finder
Description
Construct the regex_finder . Finder uses the regex engine to search for a match. Result is given in regex_search_result . This is an extension of the iterator_range. In addition it containes match results from the regex_search algorithm. Parameters MatchFlags Regex search options Rx A regular expression Returns An instance of the regex_finder object
Regex formatter.
Description
Construct the regex_formatter . Regex formatter uses the regex engine to format a match found by the regex_finder . This formatted it designed to closely cooperate with regex_finder .
194
Parameters Flags Format flags Format Regex format definition Returns An instance of the regex_formatter functor
find_iterator
Description
Find iterator encapsulates a Finder and allows for incremental searching in a string. Each increment moves the iterator to the next match. Find iterator is a readable forward traversal iterator.
195
find_iterator construct/copy/destruct
1. find_iterator(); Construct null iterator. All null iterators are equal. Postconditions eof()==true 2. find_iterator(const find_iterator & Other); Construct a copy of the find_iterator 3. template<typename FinderT>
find_iterator(IteratorT Begin, IteratorT End, FinderT Finder);
Construct new find_iterator for a given finder and a range. 4. template<typename FinderT, typename CollectionT>
find_iterator(CollectionT & Col, FinderT Finder);
1. bool eof() const; Check the eof condition. Eof condition means that there is nothing more to be searched i.e. find_iterator is after the last match.
1. const match_type & dereference() const; 2. void increment() ; 3. bool equal(const find_iterator & Other) const; Class template split_iterator boost::algorithm::split_iterator
Synopsis template<typename IteratorT> class split_iterator { public: // construct/copy/destruct split_iterator(); split_iterator(const split_iterator &); template<typename FinderT> split_iterator(IteratorT, IteratorT, FinderT); template<typename FinderT, typename CollectionT> split_iterator(CollectionT &, FinderT); // public member functions bool eof() const; // private member functions const match_type & dereference() const; void increment() ; bool equal(const split_iterator &) const;
split_iterator
196
Description
Split iterator encapsulates a Finder and allows for incremental searching in a string. Unlike the find iterator, split iterator iterates through gaps between matches. Find iterator is a readable forward traversal iterator. Dereferencing the iterator yields an iterator_range delimiting the current match.
split_iterator construct/copy/destruct
1. split_iterator(); Construct null iterator. All null iterators are equal. Postconditions eof()==true 2. split_iterator(const split_iterator & Other); Construct a copy of the split_iterator 3. template<typename FinderT>
split_iterator(IteratorT Begin, IteratorT End, FinderT Finder);
Construct new split_iterator for a given finder and a range. 4. template<typename FinderT, typename CollectionT>
split_iterator(CollectionT & Col, FinderT Finder);
1. bool eof() const; Check the eof condition. Eof condition means that there is nothing more to be searched i.e. find_iterator is after the last match.
1. const match_type & dereference() const; 2. void increment() ; 3. bool equal(const split_iterator & Other) const; Function template make_find_iterator boost::algorithm::make_find_iterator
Synopsis template<typename CollectionT, typename FinderT> find_iterator< typename result_iterator_of< CollectionT >::type > make_find_iterator(CollectionT & Collection, FinderT Finder);
197
Description
"First" finder
198
Construct the first_finder . The finder searches for the first occurrence of the string in a given input. The result is given as an iterator_range delimiting the match. Parameters Search A substring to be searched for. Returns An instance of the first_finder object
"Last" finder
Description
Construct the last_finder . The finder searches for the last occurrence of the string in a given input. The result is given as an iterator_range delimiting the match. Parameters Search A substring to be searched for. Returns An instance of the last_finder object
"Nth" finder
Description
Construct the nth_finder . The finder searches for the nth (zeroindexed) occurrence of the string in a given input. The result is given as an iterator_range delimiting the match. Parameters
199
Nth An index of the match to be find Search A substring to be searched for. Returns An instance of the nth_finder object
"Head" finder
Description
Construct the head_finder . The finder returns a head of a given input. The head is a prefix of a string up to n elements in size. If an input has less then n elements, whole input is considered a head. The result is given as an iterator_range delimiting the match. Parameters N The size of the head Returns An instance of the head_finder object
"Tail" finder
Description
Construct the tail_finder . The finder returns a tail of a given input. The tail is a suffix of a string up to n elements in size. If an input has less then n elements, whole input is considered a head. The result is given as an iterator_range delimiting the match. Parameters N The size of the head Returns An instance of the tail_finder object
200
"Token" finder
Description
Construct the token_finder . The finder searches for a token specified by a predicate. It is similar to std::find_if algorithm, with an exception that it return a range of instead of a single iterator. If "compress token mode" is enabled, adjacent matching tokens are concatenated into one match. Thus the finder can be used to search for continuous segments of characters satisfying the given predicate. The result is given as an iterator_range delimiting the match. Parameters Pred An element selection predicate eCompress Compress flag Returns An instance of the token_finder object
"Range" finder
Description
Construct the range_finder . The finder does not perform any operation. It simply returns the given range for any input. Parameters Begin Beginning of the range End End of the range Returns An instance of the range_finger object
201
Constant formatter.
Description
Construct the const_formatter . Const formatter always returns the same value, regardless of the parameter. Parameters Format A predefined value used as a result for formating Returns An instance of the const_formatter object.
Identity formatter.
Description
Construct the identity_formatter . Identity formatter always returns the parameter. Returns An instance of the identity_formatter object.
202
Empty formatter.
Description
Construct the empty_formatter . Empty formater always returns an empty sequence. Returns An instance of the empty_formatter object.
iterator_range class
// // // // // // // //
this type Encapsulated value type. Reference type. Difference type. Size type. const_iterator type iterator type Safe bool conversion.
203
Description
An iterator_range delimits a range in a sequence by beginning and ending iterators. An iterator_range can be passed to an algorithm which requires a sequence as an input. For example, the toupper() function may most frequently be used on strings, but can also be used on iterator_ranges:
boost::tolower( find( s, "UPPERCASE STRING" ) );
Many algorithms working with sequences take a pair of iterators, delimiting a working range, as arguments. The iterator_range class is an encapsulation of a range identified by a pair of iterators. It provides a collection interface, so it is possible to pass an instance to an algorithm requiring a collection as an input.
iterator_range construct/copy/destruct
1. iterator_range(); 2. iterator_range(iterator Begin, iterator End); 3. iterator_range(const std::pair< IteratorT, IteratorT > & Range); 4. iterator_range(const iterator_range & Other); 5. template<typename OtherItT>
iterator_range(const iterator_range< OtherItT > & Other);
This constructor is provided to allow conversion between const and mutable iterator instances of this class template 6. iterator_range& operator=(const iterator_range & Other); 7. template<typename OtherItT>
iterator_range& operator=(const iterator_range< OtherItT > & Other);
1. template<typename OtherItT>
bool operator==(const iterator_range< OtherItT > & Other) const;
Retrieve the begin iterator 4. IteratorT end() const; Retrieve the end iterator 5. bool empty() const; Test whether the range is empty 6. difference_type size() const; Retrieve the size of the range 7. void swap(iterator_range & Other) ; Swap two ranges 8. operator unspecified_bool_type() const; Function template operator<< boost::algorithm::operator<<
Synopsis template<typename IteratorT, typename Elem, typename Traits> std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > & Os, const iterator_range< IteratorT > & Range);
Description
Output the range to an ostream. Elements are outputed in a sequence without separators.
Description
Construct an iterator_range from a pair of iterators Parameters Begin A begin iterator End An end iterator Returns iterator_range object
205
Description
Construct an iterator_range from a std::pair<> containing the begin and end iterators. Parameters Pair A std::pair<> with begin and end iterators Returns iterator_range object
Description
Construct a new sequence of the specified type from the elements in the given range Parameters Range An input range Returns New sequence
206
Create a new sequence from the elements in the range, transformed by a function Parameters Func Transformation function Range An input range Returns New sequence
207
Description
This predicate holds when the test collection is a prefix of the Input. In other words, if the input starts with the test. When the optional predicate is specified, it is used for characterwise comparison. Parameters Comp An element comparison predicate Input An input sequence Test A test sequence Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
Description
This predicate holds when the test container is a prefix of the Input. In other words, if the input starts with the test. Elements are compared case insensitively. Parameters Input An input sequence Loc A locale used for case insensitive comparison Test A test sequence Returns
208
The result of the test Notes This function provides the strong exceptionsafety guarantee
Description
This predicate holds when the test container is a suffix of the Input. In other words, if the input ends with the test. When the optional predicate is specified, it is used for characterwise comparison. Parameters Comp An element comparison predicate Input An input sequence Test A test sequence Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
Description
This predicate holds when the test container is a suffix of the Input. In other words, if the input ends with the test. Elements are compared case insensitively. Parameters Input An input sequence Loc
209
A locale used for case insensitive comparison Test A test sequence Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
'Contains' predicate
Description
This predicate holds when the test container is contained in the Input. When the optional predicate is specified, it is used for characterwise comparison. Parameters Comp An element comparison predicate Input An input sequence Test A test sequence Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
Description
This predicate holds when the test container is contained in the Input. Elements are compared case insensitively. Parameters
210
Input An input sequence Loc A locale used for case insensitive comparison Test A test sequence Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
'Equals' predicate
Description
This predicate holds when the test container is equal to the input container i.e. all elements in both containers are same. When the optional predicate is specified, it is used for characterwise comparison. Parameters Comp An element comparison predicate Input An input sequence Test A test sequence Returns The result of the test Notes This is a twoway version of std::equal algorithm This function provides the strong exceptionsafety guarantee
211
This predicate holds when the test container is equal to the input container i.e. all elements in both containers are same. Elements are compared case insensitively. Parameters Input An input sequence Loc A locale used for case insensitive comparison Test A test sequence Returns The result of the test Notes This is a twoway version of std::equal algorithm This function provides the strong exceptionsafety guarantee
'All' predicate
Description
This predicate holds it all its elements satisfy a given condition, represented by the predicate. Parameters Input An input sequence Pred A predicate Returns The result of the test Notes This function provides the strong exceptionsafety guarantee
212
const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, match_flag_type = match_default); template<typename OutputIteratorT, typename CollectionT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> OutputIteratorT replace_regex_copy(OutputIteratorT, const CollectionT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > &, match_flag_type = match_default|format_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> SequenceT replace_regex_copy(const SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocator match_flag_type = match_default|format_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> void replace_regex(SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > &, match_flag_type = match_default|format_default); template<typename OutputIteratorT, typename CollectionT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> OutputIteratorT replace_all_regex_copy(OutputIteratorT, const CollectionT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > &, match_flag_type = match_default|format_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> SequenceT replace_all_regex_copy(const SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAlloc match_flag_type = match_default|format_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> void replace_all_regex(SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > &, match_flag_type = match_default|format_default); template<typename OutputIteratorT, typename CollectionT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT> OutputIteratorT erase_regex_copy(OutputIteratorT, const CollectionT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, match_flag_type = match_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT> SequenceT erase_regex_copy(const SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, match_flag_type = match_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT> void erase_regex(SequenceT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, match_flag_type = match_default); template<typename OutputIteratorT, typename CollectionT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT> OutputIteratorT erase_all_regex_copy(OutputIteratorT, const CollectionT &, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > &, match_flag_type = match_default);
213
Description
Search for a substring matching the given regex in the input. Parameters Flags Regex options Input A container which will be searched. Rx A regular expression Returns An iterator_range delimiting the match. Returned iterator is either InputContainerT::iterator or InputContainerT::const_iterator , depending on the constness of the input parameter. Notes This function provides the strong exceptionsafety guarantee
214
Description
Search for a substring matching given regex and format it with the specified format. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Flags Regex options Format Regex format definition Input An input string Output An output iterator to which the result will be copied Rx A regular expression Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
215
Search for a substring matching given regex and format it with the specified format. The input string is modified inplace. Parameters Flags Regex options Format Regex format definition Input An input string Rx A regular expression
template<typename OutputIteratorT, typename CollectionT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> OutputIteratorT replace_all_regex_copy(OutputIteratorT Output, const CollectionT & Input, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > & Rx, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > & Form match_flag_type Flags = match_default|format_default); template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> SequenceT replace_all_regex_copy(const SequenceT & Input, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > & Rx, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocator match_flag_type Flags = match_default|format_default);
Description
Format all substrings, matching given regex, with the specified format. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Flags Regex options Format Regex format definition Input An input string Output An output iterator to which the result will be copied Rx A regular expression Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes
216
The second variant of this function provides the strong exceptionsafety guarantee
template<typename SequenceT, typename CharT, typename RegexTraitsT, typename RegexAllocatorT, typename FormatStringTraitsT, typename FormatStringAllocatorT> void replace_all_regex(SequenceT & Input, const reg_expression< CharT, RegexTraitsT, RegexAllocatorT > & Rx, const std::basic_string< CharT, FormatStringTraitsT, FormatStringAllocatorT > & Form match_flag_type Flags = match_default|format_default);
Description
Format all substrings, matching given regex, with the specified format. The input string is modified inplace. Parameters Flags Regex options Format Regex format definition Input An input string Rx A regular expression
Description
Remove a substring matching given regex from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters
217
Flags Regex options Input An input string Output An output iterator to which the result will be copied Rx A regular expression Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Remove a substring matching given regex from the input. The input string is modified inplace. Parameters Flags Regex options Input An input string Rx A regular expression
218
Erase all substrings, matching given regex, from the input. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Flags Regex options Input An input string Output An output iterator to which the result will be copied Rx A regular expression Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Erase all substrings, matching given regex, from the input. The input string is modified inplace. Parameters Flags Regex options Input An input string Rx A regular expression
219
Description
This algorithm finds all substrings matching the give regex in the input. Each part is copied and added as a new element to the output container. Thus the result container must be able to hold copies of the matches (in a compatible structure like std::string) or a reference to it (e.g. using the iterator range class). Examples of such a container are std::vector<std::string> or std::list<boost::iterator_range<std::string::iterator>> Parameters Flags Regex options Input A container which will be searched. Result A container that can hold copies of references to the substrings. Rx A regular expression Returns A reference to the result Notes Prior content of the result will be overwritten. This function provides the strong exceptionsafety guarantee
Description
Tokenize expression. This function is equivalent to C strtok. Input sequence is split into tokens, separated by separators. Separator is an every match of the given regex. Each part is copied and added as a new element to the output container. Thus the result container must be able to hold copies of the matches (in a compatible structure like std::string) or a reference to it (e.g. using the iterator range class). Examples of such a container are std::vector<std::string> or std::list<boost::iterator_range<std::string::iterator>> Parameters Flags Regex options
220
Input A container which will be searched. Result A container that can hold copies of references to the substrings. Rx A regular expression Returns A reference to the result Notes Prior content of the result will be overwritten. This function provides the strong exceptionsafety guarantee
"Regex" finder
Description
Construct the regex_finder . Finder uses the regex engine to search for a match. Result is given in regex_search_result . This is an extension of the iterator_range. In addition it containes match results from the regex_search algorithm. Parameters MatchFlags Regex search options Rx A regular expression Returns An instance of the regex_finder object
221
Regex formatter.
Description
Construct the regex_formatter . Regex formatter uses the regex engine to format a match found by the regex_finder . This formatted it designed to closely cooperate with regex_finder . Parameters Flags Format flags Format Regex format definition Returns An instance of the regex_formatter functor
222
223
template<typename OutputIteratorT, typename Collection1T, typename Collection2T> OutputIteratorT replace_range_copy(OutputIteratorT Output, const Collection1T & Input, const iterator_range< typename const_iterator_of< Collection1T >::type > & SearchRange, const Collection2T & Format); template<typename SequenceT, typename CollectionT> SequenceT replace_range_copy(const SequenceT & Input, const iterator_range< typename const_iterator_of< SequenceT >::type > & Searc const CollectionT & Format);
Description
Replace the given range in the input string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator.
224
Parameters Format A substitute string Input An input string Output An output iterator to which the result will be copied SearchRange A range in the input to be substituted Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace the given range in the input string. The input sequence is modified inplace. Parameters Format A substitute string Input An input string SearchRange A range in the input to be substituted
225
Replace the first match of the search substring in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
replace the first match of the search substring in the input with the format string. The input sequence is modified inplace. Parameters Format A substitute string Input An input string Search A substring to be searched for
226
Description
Replace the first match of the search substring in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace the first match of the search substring in the input with the format string. Input sequence is modified inplace. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Search A substring to be searched for
227
Description
Replace the last match of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace the last match of the search string in the input with the format string. Input sequence is modified inplace. Parameters Format A substitute string Input
228
Description
Replace the last match of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
229
Replace the last match of the search string in the input with the format string.The input sequence is modified inplace. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Search A substring to be searched for Returns A reference to the modified input
Description
Replace an Nth (zeroindexed) match of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string Nth An index of the match to be replaced. The index is 0based. Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes
230
The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace an Nth (zeroindexed) match of the search string in the input with the format string. Input sequence is modified inplace. Parameters Format A substitute string Input An input string Nth An index of the match to be replaced. The index is 0based. Search A substring to be searched for
Description
Replace an Nth (zeroindexed) match of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Format A substitute string
231
Input An input string Loc A locale used for case insensitive comparison Nth An index of the match to be replaced. The index is 0based. Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace an Nth (zeroindexed) match of the search string in the input with the format string. Input sequence is modified inplace. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Nth An index of the match to be replaced. The index is 0based. Search A substring to be searched for
232
Description
Replace all occurrences of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace all occurrences of the search string in the input with the format string. The input sequence is modified inplace. Parameters Format A substitute string Input An input string Search A substring to be searched for Returns A reference to the modified input
233
Description
Replace all occurrences of the search string in the input with the format string. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Searching is case insensitive. Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Output An output iterator to which the result will be copied Search A substring to be searched for Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Description
Replace all occurrences of the search string in the input with the format string.The input sequence is modified inplace. Searching is case insensitive.
234
Parameters Format A substitute string Input An input string Loc A locale used for case insensitive comparison Search A substring to be searched for
Description
Replace the head of the input with the given format string. The head is a prefix of a string of given size. If the sequence is shorter then required, whole string if considered to be the head. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string N Length of the head Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
235
Description
Replace the head of the input with the given format string. The head is a prefix of a string of given size. If the sequence is shorter then required, the whole string is considered to be the head. The input sequence is modified inplace. Parameters Format A substitute string Input An input string N Length of the head
Description
Replace the tail of the input with the given format string. The tail is a suffix of a string of given size. If the sequence is shorter then required, whole string is considered to be the tail. The result is a modified copy of the input. It is returned as a sequence or copied to the output iterator. Parameters Format A substitute string Input An input string N Length of the tail Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a modified copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
236
Description
Replace the tail of the input with the given format sequence. The tail is a suffix of a string of given size. If the sequence is shorter then required, the whole string is considered to be the tail. The input sequence is modified inplace. Parameters Format A substitute string Input An input string N Length of the tail
237
Description
This trait specifies that the sequence has std::string like replace method
Description
This trait specifies that the sequence has stable iterators. It means that operations like insert/erase/replace do not invalidate iterators.
238
This trait specifies that the sequence's insert method has constant time complexity.
Description
This trait specifies that the sequence's erase method has constant time complexity.
239
Description
This algorithm finds all occurrences of the search string in the input. Each part is copied and added as a new element to the output container. Thus the result container must be able to hold copies of the matches (in a compatible structure like std::string) or a reference to it (e.g. using the iterator range class). Examples of such a container are std::vector<std::string> or std::list<boost::iterator_range<std::string::iterator>> Parameters Input A container which will be searched. Result A container that can hold copies of references to the substrings Search A substring to be searched for. Returns A reference the result Notes Prior content of the result will be overwritten. This function provides the strong exceptionsafety guarantee
240
This algorithm finds all occurrences of the search string in the input. Each part is copied and added as a new element to the output container. Thus the result container must be able to hold copies of the matches (in a compatible structure like std::string) or a reference to it (e.g. using the iterator range class). Examples of such a container are std::vector<std::string> or std::list<boost::iterator_range<std::string::iterator>> Searching is case insensitive. Parameters Input A container which will be searched. Loc A locale used for case insensitive comparison Result A container that can hold copies of references to the substrings Search A substring to be searched for. Returns A reference the result Notes Prior content of the result will be overwritten. This function provides the strong exceptionsafety guarantee
Split algorithm.
Description
Tokenize expression. This function is equivalent to C strtok. Input sequence is split into tokens, separated by separators. Separators are given by means of the predicate. Each part is copied and added as a new element to the output container. Thus the result container must be able to hold copies of the matches (in a compatible structure like std::string) or a reference to it (e.g. using the iterator range class). Examples of such a container are std::vector<std::string> or std::list<boost::iterator_range<std::string::iterator>> Parameters Input A container which will be searched. Pred A predicate to identify separators. This predicate is supposed to return true if a given element is a separator. Result
241
A container that can hold copies of references to the substrings eCompress If eCompress argument is set to token_compress_on, adjacent separators are merged together. Otherwise, every two separators delimit a token. Returns A reference the result Notes Prior content of the result will be overwritten. This function provides the strong exceptionsafety guarantee
242
Description
Remove all leading spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The result is a trimmed copy of the input. It is returned as a sequence or copied to the output iterator Parameters Input An input collection IsSpace An unary predicate identifying spaces Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
243
Remove all leading spaces from the input. The result is a trimmed copy of the input. Parameters Input An input sequence Loc a locale used for 'space' classification Returns A trimmed copy of the input Notes This function provides the strong exceptionsafety guarantee
Left trim.
Description
Remove all leading spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The input sequence is modified inplace. Parameters Input An input sequence IsSpace An unary predicate identifying spaces
Left trim.
Description
Remove all leading spaces from the input. The Input sequence is modified inplace. Parameters Input An input sequence
244
Description
Remove all trailing spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The result is a trimmed copy of the input. It is returned as a sequence or copied to the output iterator Parameters Input An input collection IsSpace An unary predicate identifying spaces Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Right trim.
Description
Remove all trailing spaces from the input. The result is a trimmed copy of the input Parameters Input An input sequence Loc A locale used for 'space' classification
245
Returns A trimmed copy of the input Notes This function provides the strong exceptionsafety guarantee
Description
Remove all trailing spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The input sequence is modified inplace. Parameters Input An input sequence IsSpace An unary predicate identifying spaces
Right trim.
Description
Remove all trailing spaces from the input. The input sequence is modified inplace. Parameters Input An input sequence Loc A locale used for 'space' classification
246
Description
Remove all trailing and leading spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The result is a trimmed copy of the input. It is returned as a sequence or copied to the output iterator Parameters Input An input collection IsSpace An unary predicate identifying spaces Output An output iterator to which the result will be copied Returns An output iterator pointing just after the last inserted character or a copy of the input Notes The second variant of this function provides the strong exceptionsafety guarantee
Trim.
Description
Remove all leading and trailing spaces from the input. The result is a trimmed copy of the input Parameters Input An input sequence Loc A locale used for 'space' classification Returns A trimmed copy of the input Notes This function provides the strong exceptionsafety guarantee
247
Trim.
Description
Remove all leading and trailing spaces from the input. The supplied predicate is used to determine which characters are considered spaces. The input sequence is modified inplace. Parameters Input An input sequence IsSpace An unary predicate identifying spaces
Trim.
Description
Remove all leading and trailing spaces from the input. The input sequence is modified inplace. Parameters Input An input sequence Loc A locale used for 'space' classification
7. Rationale
7.1. Locales
Locales have a very close relation to string processing. They contain information about the character sets and are used, for example, to change the case of characters and to classify the characters. C++ allows to work with multiple different instances of locales at once. If an algorithm manipulates some data in a way that requires the usage of locales, there must be a way to specify them. However, one instance of locales is sufficient for most of the applications, and for a user it could be very tedious to specify which locales to use at every place where it is needed. Fortunately, the C++ standard allows to specify the global locales (using static member function std:locale::global()). When instantiating an std::locale class without explicit information, the instance will
248
be initialized with the global locale. This implies, that if an algorithm needs a locale, it should have an std::locale parameter defaulting to std::locale(). If a user needs to specify locales explicitly, she can do so. Otherwise the global locales are used.
8. Environment
8.1. Build
The whole library is provided in headers. Regex variants of some algorithms, however, are dependent on the Boost.Regex library. All such algorithms are separated in boost/algorithm/string_regex.hpp. If this header is used, the application must be linked with the Boost.Regex library.
8.2. Examples
Examples showing the basic usage of the library can be found in the libs/algorithm/string/example directory. There is a separate file for the each part of the library. Please follow the boost build guidelines to build examples using the bjam. To successfully build regex examples the Boost.Regex library is required.
8.3. Tests
A full set of test cases for the library is located in the libs/algorithm/string/test directory. The test cases can be executed using the boost build system. For the tests of regular expression variants of algorithms, the Boost.Regex library is required.
8.4. Portability
The library has been successfully compiled and tested with the following compilers: Microsoft Visual C++ 7.0 Microsoft Visual C++ 7.1 GCC 3.2 GCC 3.3.1 See Boost regression tables for additional info for a particular compiler. There are known limitation on platforms not supporting partial template specialization. Library depends on correctly implemented std::iterator_traits class. If a standard library provided with compiler is broken, the String Algorithm Library cannot function properly. Usually it implies that primitive pointer iterators are not working with the library functions.
9. Credits
9.1. Acknowledgments
The author would like to thank everybody who gave suggestions and comments. Especially valuable were the contributions of Thorsten Ottosen, Jeff Garland and the other boost members who participated in the review process, namely David Abrahams, Daniel Frey, Beman Dawes, John Maddock, David B.Held, Pavel Vozenilek and many other. Additional thanks go to Stefan Slapeta and Toon Knapen, who have been very resourceful in solving various portability
249
issues.
250
Chapter 9. Boost.Threads
William E. Kempf Copyright 2001, 2002, 2003 William E. Kempf
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 appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. William E. Kempf makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.
1. Overview
1.1. Introduction
Boost.Threads allows C++ programs to execute as multiple, asynchronous, independent threadsofexecution. Each thread has its own machine state including program instruction counter and registers. Programs which execute as multiple threads are called multithreaded programs to distinguish them from traditional singlethreaded programs. The glossary gives a more complete description of the multithreading execution environment. Multithreading provides several advantages: Programs which would otherwise block waiting for some external event can continue to respond if the blocking operation is placed in a separate thread. Multithreading is usually an absolute requirement for these programs. Welldesigned multithreaded programs may execute faster than singlethreaded programs, particularly on multiprocessor hardware. Note, however, that poorlydesigned multithreaded programs are often slower than singlethreaded programs. Some program designs may be easier to formulate using a multithreaded approach. After all, the real world is asynchronous!
1.2. Dangers
1.2.1. General considerations Beyond the errors which can occur in singlethreaded programs, multithreaded programs are subject to additional errors: Race conditions Deadlock (sometimes called "deadly embrace") Priority failures (priority inversion, infinite overtaking, starvation, etc.) Every multithreaded program must be designed carefully to avoid these errors. These aren't rare or exotic failures they are virtually guaranteed to occur unless multithreaded code is designed to avoid them. Priority failures are somewhat less common, but are nonetheless serious. The Boost.Threads design attempts to minimize these errors, but they will still occur unless the programmer proactively designs to avoid them.
Note
Please also see Section 9, Implementation Notes for additional, implementationspecific considerations.
251
Chapter 9. Boost.Threads
1.2.2. Testing and debugging considerations Multithreaded programs are nondeterministic. In other words, the same program with the same input data may follow different execution paths each time it is invoked. That can make testing and debugging a nightmare: Failures are often not repeatable. Probe effect causes debuggers to produce very different results from nondebug uses. Debuggers require special support to show thread state. Tests on a single processor system may give no indication of serious errors which would appear on multiprocessor systems, and visa versa. Thus test cases should include a varying number of processors. For programs which create a varying number of threads according to workload, tests which don't span the full range of possibilities may miss serious errors. 1.2.3. Getting a head start Although it might appear that multithreaded programs are inherently unreliable, many reliable multithreaded programs do exist. Multithreading techniques are known which lead to reliable programs. Design patterns for reliable multithreaded programs, including the important monitor pattern, are presented in PatternOriented Software Architecture Volume 2 Patterns for Concurrent and Networked Objects[SchmidtStalRohnertBuschmann]. Many important multithreading programming considerations (independent of threading library) are discussed in Programming with POSIX Threads[Butenhof97]. Doing some reading before attempting multithreaded designs will give you a head start toward reliable multithreaded programs.
252
Chapter 9. Boost.Threads
2. Design
With client/server and threetier architectures becoming common place in today's world, it's becoming increasingly important for programs to be able to handle parallel processing. Modern day operating systems usually provide some support for this through native thread APIs. Unfortunately, writing portable code that makes use of parallel processing in C++ is made very difficult by a lack of a standard interface for these native APIs. Further, these APIs are almost universally C APIs and fail to take advantage of C++'s strengths, or to address concepts unique to C++, such as exceptions. The Boost.Threads library is an attempt to define a portable interface for writing parallel processes in C++.
2.1. Goals
The Boost.Threads library has several goals that should help to set it apart from other solutions. These goals are listed in order of precedence with full descriptions below. Portability Boost.Threads was designed to be highly portable. The goal is for the interface to be easily implemented on any platform that supports threads, and possibly even on platforms without native thread support. Safety Boost.Threads was designed to be as safe as possible. Writing threadsafe code is very difficult and successful libraries must strive to insulate the programmer from dangerous constructs as much as possible. This is accomplished in several ways: C++ language features are used to make correct usage easy (if possible) and errorprone usage impossible or at least more difficult. For example, see the Mutex and Lock designs, and note how they interact. Certain traditional concurrent programming features are considered so errorprone that they are not provided at all. For example, see Section 4.5, Rationale for not providing Event Variables . Dangerous features, or features which may be misused, are identified as such in the documentation to make users aware of potential pitfalls. Flexibility Boost.Threads was designed to be flexible. This goal is often at odds with safety. When functionality might be compromised by the desire to keep the interface safe, Boost.Threads has been designed to provide the functionality, but to make it's use prohibitive for general use. In other words, the interfaces have been designed such that it's usually obvious when something is unsafe, and the documentation is written to explain why. Efficiency
253
Chapter 9. Boost.Threads
Boost.Threads was designed to be as efficient as possible. When building a library on top of another library there is always a danger that the result will be so much slower than the "native" API that programmers are inclined to ignore the higher level API. Boost.Threads was designed to minimize the chances of this occurring. The interfaces have been crafted to allow an implementation the greatest chance of being as efficient as possible. This goal is often at odds with the goal for safety. Every effort was made to ensure efficient implementations, but when in conflict safety has always taken precedence.
3. Concepts
Boost.Threads currently supports two types of mutex concepts: ordinary Mutexes, which allow only one thread at a time to access a resource, and Read/Write Mutexes, which allow only one thread at a time to access a resource when it is being modified (the "Write" part of Read/Write), but allows multiple threads to access a resource when it is only being referenced (the "Read" part of Read/Write).
254
Chapter 9. Boost.Threads
With a recursive locking strategy, when a thread attempts to acquire a lock on the mutex object for which it already owns a lock, the operation is successful. Note the distinction between a thread, which may have multiple locks outstanding on a recursive mutex object, and a lock object, which even for a recursive mutex object cannot have any of its lock functions called multiple times without first calling unlock. Internally a lock count is maintained and the owning thread must unlock the mutex object the same number of times that it locked it before the mutex object's state returns to unlocked. Since mutex objects in Boost.Threads expose locking functionality only through lock concepts, a thread will always unlock a mutex object the same number of times that it locked it. This helps to eliminate a whole set of errors typically found in traditional C style thread APIs. Classes boost::recursive_mutex, boost::recursive_try_mutex and boost::recursive_timed_mutex use this locking strategy.
3.1.1.2. Checked Locking Strategy
With a checked locking strategy, when a thread attempts to acquire a lock on the mutex object for which the thread already owns a lock, the operation will fail with some sort of error indication. Further, attempts by a thread to unlock a mutex object that was not locked by the thread will also return some sort of error indication. In Boost.Threads, an exception of type boost::lock_error would be thrown in these cases. Boost.Threads does not currently provide any mutex objects that use this strategy.
255
Chapter 9. Boost.Threads
3.1.1.3. Unchecked Locking Strategy
With an unchecked locking strategy, when a thread attempts to acquire a lock on a mutex object for which the thread already owns a lock the operation will deadlock. In general this locking strategy is less safe than a checked or recursive strategy, but it's also a faster strategy and so is employed by many libraries. Boost.Threads does not currently provide any mutex objects that use this strategy.
3.1.1.4. Unspecified Locking Strategy
With an unspecified locking strategy, when a thread attempts to acquire a lock on a mutex object for which the thread already owns a lock the operation results in undefined behavior. In general a mutex object with an unspecified locking strategy is unsafe, and it requires programmer discipline to use the mutex object properly. However, this strategy allows an implementation to be as fast as possible with no restrictions on its implementation. This is especially true for portable implementations that wrap the native threading support of a platform. For this reason, the classes boost::mutex, boost::try_mutex and boost::timed_mutex use this locking strategy despite the lack of safety. 3.1.2. Scheduling Policies Every mutex object follows one of several scheduling policies. These policies define the semantics when the mutex object is unlocked and there is more than one thread waiting to acquire a lock. In other words, the policy defines which waiting thread shall acquire the lock.
3.1.2.1. FIFO Scheduling Policy
With a FIFO ("First In First Out") scheduling policy, threads waiting for the lock will acquire it in a firstcomefirstserved order. This can help prevent a high priority thread from starving lower priority threads that are also waiting on the mutex object's lock.
3.1.2.2. Priority Driven Policy
With a Priority Driven scheduling policy, the thread with the highest priority acquires the lock. Note that this means that lowpriority threads may never acquire the lock if the mutex object has high contention and there is always at least one highpriority thread waiting. This is known as thread starvation. When multiple threads of the same priority are waiting on the mutex object's lock one of the other scheduling priorities will determine which thread shall acquire the lock.
3.1.2.3. Unspecified Policy
The mutex object does not specify a scheduling policy. In order to ensure portability, all Boost.Threads mutex objects use an unspecified scheduling policy. 3.1.3. Mutex Concepts
3.1.3.1. Mutex Concept
A Mutex object has two states: locked and unlocked. Mutex object state can only be determined by a lock object meeting the appropriate lock concept requirements and constructed for the Mutex object. A Mutex is NonCopyable. For a Mutex type M and an object m of that type, the following expressions must be wellformed and have the indicated effects.
Chapter 9. Boost.Threads
Effects
A TryMutex is a refinement of Mutex. For a TryMutex type M and an object m of that type, the following expressions must be wellformed and have the indicated effects.
A TimedMutex is a refinement of TryMutex. For a TimedMutex type M and an object m of that type, the following expressions must be wellformed and have the indicated effects.
Table 9.3. TimedMutex Expressions Expression M::scoped_timed_lock 3.1.4. Mutex Models Boost.Threads currently supplies six models of Mutex and its refinements. Effects A model of ScopedTimedLock
Table 9.4. Mutex Models Concept Mutex boost::recursive_mutex boost::try_mutex TryMutex Mutex boost::recursive_try_mutex boost::timed_mutex TimedMutex TryMutex boost::recursive_timed_mutex Refines boost::mutex Models
257
Chapter 9. Boost.Threads
3.1.5. Lock Concepts A lock object provides a safe means for locking and unlocking a mutex object (an object whose type is a model of Mutex or one of its refinements). In other words they are an implementation of the Scoped Locking[SchmidtStalRohnertBuschmann] pattern. The ScopedLock, ScopedTryLock, and ScopedTimedLock concepts formalize the requirements. Lock objects are constructed with a reference to a mutex object and typically acquire ownership of the mutex object by setting its state to locked. They also ensure ownership is relinquished in the destructor. Lock objects also expose functions to query the lock status and to manually lock and unlock the mutex object. Lock objects are meant to be short lived, expected to be used at block scope only. The lock objects are not threadsafe. Lock objects must maintain state to indicate whether or not they've been locked and this state is not protected by any synchronization concepts. For this reason a lock object should never be shared between multiple threads.
3.1.5.1. Lock Concept
For a Lock type L and an object lk and const object clk of that type, the following expressions must be wellformed and have the indicated effects.
Table 9.5. Lock Expressions Expression (&lk)>~L(); (&clk)>operator const void*() clk.locked() if (locked()) unlock(); Returns type void*, nonzero if the associated mutex object has been locked by clk, otherwise 0. Returns a bool, (&clk)>operator const void*() != 0 Throws boost::lock_error if locked(). If the associated mutex object is already locked by some other thread, places the current thread in the Blocked state until the associated mutex is unlocked, after which the current thread is placed in the Ready state, eventually to be returned to the Running state. If the associated mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated mutex object. Postcondition: locked() == true Throws boost::lock_error if !locked(). lk.unlock() Unlocks the associated mutex. Postcondition: !locked()
3.1.5.2. ScopedLock Concept
Effects
lk.lock()
A ScopedLock is a refinement of Lock. For a ScopedLock type L and an object lk of that type, and an object m of a type meeting the Mutex requirements, and an object b of type bool, the following expressions must be wellformed and have the indicated effects.
258
Chapter 9. Boost.Threads
Effects Constructs an object lk, and associates mutex object m with it, then calls lock() Constructs an object lk, and associates mutex object m with it, then if b, calls lock()
A TryLock is a refinement of Lock. For a TryLock type L and an object lk of that type, the following expressions must be wellformed and have the indicated effects.
Table 9.7. TryLock Expressions Expression Throws boost::lock_error if locked(). lk.try_lock() Makes a nonblocking attempt to lock the associated mutex object, returning true if the lock attempt is successful, otherwise false. If the associated mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated mutex object.
3.1.5.4. ScopedTryLock Concept
Effects
A ScopedTryLock is a refinement of TryLock. For a ScopedTryLock type L and an object lk of that type, and an object m of a type meeting the TryMutex requirements, and an object b of type bool, the following expressions must be wellformed and have the indicated effects.
Table 9.8. ScopedTryLock Expressions Expression L lk(m); L lk(m,b); Effects Constructs an object lk, and associates mutex object m with it, then calls try_lock() Constructs an object lk, and associates mutex object m with it, then if b, calls lock()
A TimedLock is a refinement of TryLock. For a TimedLock type L and an object lk of that type, and an object t of type boost::xtime, the following expressions must be wellformed and have the indicated effects.
Table 9.9. TimedLock Expressions Expression Throws boost::lock_error if locked(). lk.timed_lock(t) Makes a blocking attempt to lock the associated mutex object, and returns true if successful within the specified time t, otherwise false. If the associated mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated mutex object. Effects
259
Chapter 9. Boost.Threads
3.1.5.6. ScopedTimedLock Concept
A ScopedTimedLock is a refinement of TimedLock. For a ScopedTimedLock type L and an object lk of that type, and an object m of a type meeting the TimedMutex requirements, and an object b of type bool, and an object t of type boost::xtime, the following expressions must be wellformed and have the indicated effects.
Table 9.10. ScopedTimedLock Expressions Expression L lk(m,t); L lk(m,b); 3.1.6. Lock Models Boost.Threads currently supplies twelve models of Lock and its refinements. Effects Constructs an object lk, and associates mutex object m with it, then calls timed_lock(t) Constructs an object lk, and associates mutex object m with it, then if b, calls lock()
Table 9.11. Lock Models Concept Lock boost::mutex::scoped_lock boost::recursive_mutex::scoped_lock boost::try_mutex::scoped_lock ScopedLock Lock boost::recursive_try_mutex::scoped_lock boost::timed_mutex::scoped_lock boost::recursive_timed_mutex::scoped_lock TryLock Lock boost::try_mutex::scoped_try_lock boost::recursive_try_mutex::scoped_try_lock ScopedTryLock TryLock boost::timed_mutex::scoped_try_lock boost::recursive_timed_mutex::scoped_try_lock TimedLock ScopedTimedLock TryLock boost::timed_mutex::scoped_timed_lock TimedLock boost::recursive_timed_mutex::scoped_timed_lock Refines Models
260
Chapter 9. Boost.Threads
With a recursive locking strategy, when a thread attempts to acquire a lock on a read/write mutex object for which it already owns a lock, the operation is successful, except in the case where a thread holding a readlock attempts to obtain a write lock, in which case a boost::lock_error exception will be thrown. Note the distinction between a thread, which may have multiple locks outstanding on a recursive read/write mutex object, and a lock object, which even for a recursive read/write mutex object cannot have any of its lock functions called multiple times without first calling unlock. Lock Type Held readlock readlock writelocked writelocked Lock Type Requested readlock writelock readlock writelock Grant the readlock immediately If this thread is the only holder of the readlock, grants the write lock immediately. Otherwise throws a boost::lock_error exception. Grants the (additional) readlock immediately. Grant the writelock immediately
Action
261
Chapter 9. Boost.Threads
Internally a lock count is maintained and the owning thread must unlock the mutex object the same number of times that it locked it before the mutex object's state returns to unlocked. Since mutex objects in Boost.Threads expose locking functionality only through lock concepts, a thread will always unlock a mutex object the same number of times that it locked it. This helps to eliminate a whole set of errors typically found in traditional C style thread APIs. Boost.Threads does not currently provide any read/write mutex objects that use this strategy. A successful implementation of this locking strategy may require thread identification.
3.2.1.2. Checked Locking Strategy
With a checked locking strategy, when a thread attempts to acquire a lock on the mutex object for which the thread already owns a lock, the operation will fail with some sort of error indication, except in the case of multiple readlock acquisition which is a normal operation for ANY ReadWriteMutex. Further, attempts by a thread to unlock a mutex that was not locked by the thread will also return some sort of error indication. In Boost.Threads, an exception of type boost::lock_error would be thrown in these cases. Lock Type Held readlock readlock writelocked writelocked Lock Type Requested readlock writelock readlock writelock Action Grant the readlock immediately Throw boost::lock_error Throw boost::lock_error Throw boost::lock_error
Boost.Threads does not currently provide any read/write mutex objects that use this strategy. A successful implementation of this locking strategy may require thread identification.
3.2.1.3. Unchecked Locking Strategy
With an unchecked locking strategy, when a thread attempts to acquire a lock on the read/write mutex object for which the thread already owns a lock, the operation will deadlock. In general this locking strategy is less safe than a checked or recursive strategy, but it can be a faster strategy and so is employed by many libraries. Lock Type Held readlock readlock writelocked writelocked Lock Type Requested readlock writelock readlock writelock Action Grant the readlock immediately Deadlock Deadlock Deadlock
Boost.Threads does not currently provide any mutex objects that use this strategy. For ReadWriteMutexes on platforms that contain natively recursive synchronization primitives, implementing a guaranteeddeadlock can actually involve extra work, and would likely require thread identification.
3.2.1.4. Unspecified Locking Strategy
With an unspecified locking strategy, when a thread attempts to acquire a lock on a read/write mutex object for which the thread already owns a lock, the operation results in undefined behavior. When a read/write mutex object has an unspecified locking strategy the programmer must assume that the read/write mutex object instead uses an unchecked strategy as the worse case, although some platforms may exhibit a mix of unchecked and recursive behavior. Lock Type Held Lock Type Requested Action
262
Chapter 9. Boost.Threads
Grant the readlock immediately Undefined, but generally deadlock Undefined, but generally deadlock Undefined, but generally deadlock
In general a read/write mutex object with an unspecified locking strategy is unsafe, and it requires programmer discipline to use the read/write mutex object properly. However, this strategy allows an implementation to be as fast as possible with no restrictions on its implementation. This is especially true for portable implementations that wrap the native threading support of a platform. For this reason, the classes read_write_mutex, try_read_write_mutex, and timed_read_write_mutex use this locking strategy despite the lack of safety.
3.2.1.5. Thread Identification
ReadWriteMutexes can support specific Locking Strategies (recursive and checked) which help to detect and protect against selfdeadlock. Selfdeadlock can occur when a holder of a locked ReadWriteMutex attempts to obtain another lock. Given an implemention I which is susceptible to selfdeadlock but otherwise correct and efficient, a recursive or checked implementation Ir or Ic can use the same basic implementation, but make special checks against selfdeadlock by tracking the identities of thread(s) currently holding locks. This approach makes deadlock detection othrogonal to the basic ReadWriteMutex implementaion. Alternatively, a different basic implementation for ReadWriteMutex concepts, I' (IPrime) may exist which uses recursive or checked versions of synchronization primitives to produce a recursive or checked ReadWriteMutex while still providing flexibility in terms of Scheduling Policies. Please refer to the Boost.Threadsread/write mutex concept documentation for a discussion of locking strategies. The read/write mutex supports only the unspecified locking strategy. ReadWriteMutexes are parameterized on a Mutex type which they use to control writelocking and access to internal state.
3.2.1.6. Lock Promotion
ReadWriteMutexes can support lock promotion, where a mutex which is in the readlocked state transitions to a writelocked state without releasing the lock. Lock promotion can be tricky to implement; for instance, extra care must be taken to ensure that only one thread holding a readlock can block awaiting promotion at any given time. If more than one readlock holder is allowed to enter a blocked state while waiting to be promoted, deadlock will result since both threads will be waiting for the other to release their readlock. Currently, Boost.Threads supports lock promotion through promote(), try_promote(), and timed_promote() operations.
3.2.1.7. Lock Demotion
ReadWriteMutexes can support lock demotion, where a mutex which is in the writelocked state transitions to a readlocked state without releasing the lock. Since by definition only one thread at a time may hold a writelock, the problem with deadlock that can occur during lock promotion is not a problem for lock demotion. Currently, Boost.Threads supports lock demotion through demote(), try_demote(), and timed_demote() operations. 3.2.2. Scheduling Policies Every read/write mutex object follows one of several scheduling policies. These policies define the semantics when the mutex object is unlocked and there is more than one thread waiting to acquire a lock. In other words, the policy defines which waiting thread shall acquire the lock. For a read/write mutex, it is particularly important to define the behavior when threads are requesting both read and write access simultaneously. This will be referred to as "interclass scheduling" because
263
Chapter 9. Boost.Threads
it describes the scheduling between two classes of threads (those waiting for a read lock and those waiting for a write lock). For some types of interclass scheduling, an "intraclass" scheduling policy can also be defined that will describe the order in which waiting threads of the same class (i.e., those waiting for the same type of lock) will acquire the thread.
3.2.2.1. InterClass Scheduling Policies
3.2.2.1.1. ReaderPriority
With ReaderPriority scheduling, any pending request for a readlock will have priority over a pending request for a writelock, irrespective of the current lock state of the read/write mutex, and irrespective of the relative order that the pending requests arrive. Current mutex state unlocked readlocked Request Type readlock readlock Grant the readlock immediately Grant the additional readlock immediately. Wait to acquire the lock until the thread holding the writelock releases its lock (or until the specified time, if any). A readlock will be granted to all pending readers before any other thread can acquire a writelock. TODO: trylock, timedlock. Grant the writelock immediately, if and only if there are no pending readlock requests. unlocked writelock TODO: trylock, timedlock. Wait to acquire the lock until all threads holding readlocks release their locks AND no requests for readlocks exist. If other writelock requests exist, the lock is granted in accordance with the intraclass scheduling policy. TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock AND no requests for readlocks exist. If other writelock requests exist, the lock is granted in accordance with the intraclass scheduling policy. TODO: trylock, timedlock. readlocked writelocked
3.2.2.1.2. WriterPriority
Action
writelocked
readlock
readlocked
writelock
writelocked
writelock
promote demote
TODO TODO
With WriterPriority scheduling, any pending request for a writelock will have priority over a pending request for a readlock, irrespective of the current lock state of the read/write mutex, and irrespective of the relative order that the pending requests arrive. Current mutex state unlocked readlocked Request Type readlock readlock Grant the readlock immediately. Grant the additional readlock immediately, IF no outstanding requests for a writelock
Action
264
Chapter 9. Boost.Threads
exist; otherwise TODO. TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock. The read lock will be granted once no other outstanding writelock requests exist. TODO: trylock, timedlock. unlocked writelock Grant the writelock immediately. Wait to acquire the lock until all threads holding readlocks release their locks. If other writelock requests exist, the lock is granted in accordance with the intraclass scheduling policy. This request will be granted before any new readlock requests are granted. TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock. If other writelock requests exist, the lock is granted in accordance with the intraclass scheduling policy. This request will be granted before any new readlock requests are granted. TODO: trylock, timedlock. readlocked writelocked promote demote TODO TODO
writelocked
readlock
readlocked
writelock
writelocked
writelock
3.2.2.1.3. AlternatingPriority/ManyReads
With AlternatingPriority/ManyReads scheduling, reader or writer starvation is avoided by alternatively granting read or write access when pending requests exist for both types of locks. Outstanding readlock requests are treated as a group when it is the "readers' turn" Current mutex state unlocked
Action
readlocked
readlock
Grant the additional readlock immediately, IF no outstanding requests for a writelock exist. If outstanding writelock requests exist, this lock will not be granted until at least one of the writelocks is granted and released. If other readlock requests exist, all readlocks will be granted as a group. TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock. If other outstanding writelock requests exist, they will have to wait until all current readlock requests are serviced. TODO: trylock, timedlock.
writelocked
readlock
unlocked readlocked
writelock writelock
Grant the writelock immediately. Wait to acquire the lock until all threads holding readlocks release their locks. If other writelock requests exist, this lock will be granted to one of them in accordance with the intraclass scheduling policy.
265
Chapter 9. Boost.Threads
TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock. If other outstanding readlock requests exist, this lock will not be granted until all of the currently waiting readlocks are granted and released. If other writelock requests exist, this lock will be granted in accordance with the intraclass scheduling policy. TODO: trylock, timedlock. readlocked writelocked promote demote TODO TODO
writelocked
writelock
3.2.2.1.4. AlternatingPriority/SingleRead
With AlternatingPriority/SingleRead scheduling, reader or writer starvation is avoided by alternatively granting read or write access when pending requests exist for both types of locks. Outstanding readlock requests are services one at a time when it is the "readers' turn" Current mutex state unlocked Request Type readlock Grant the readlock immediately. Grant the additional readlock immediately, IF no outstanding requests for a writelock exist. If outstanding writelock requests exist, this lock will not be granted until at least one of the writelocks is granted and released. TODO: trylock, timedlock. Wait to acquire the lock until the thread holding the writelock releases its lock. writelocked readlock If other outstanding writelock requests exist, exactly one readlock request will be granted before the next writelock is granted. TODO: trylock, timedlock. unlocked writelock Grant the writelock immediately. Wait to acquire the lock until all threads holding readlocks release their locks. readlocked writelock If other writelock requests exist, this lock will be granted to one of them in accordance with the intraclass scheduling policy. Wait to acquire the lock until the thread holding the writelock releases its lock. If other outstanding readlock requests exist, this lock can not be granted until exactly one readlock request is granted and released. If other writelock requests exist, this lock will be granted in accordance with the intraclass scheduling policy. TODO: trylock, timedlock. readlocked writelocked promote demote TODO TODO
Action
readlocked
readlock
writelocked
writelock
266
Chapter 9. Boost.Threads
3.2.2.2. IntraClass Scheduling Policies
Please refer to Section 3.1.2, Scheduling Policies for a discussion of mutex scheduling policies, which are identical to read/write mutex intraclass scheduling policies. For threads waiting to obtain writelocks, the read/write mutex supports only the Unspecified intraclass scheduling policy. That is, given a set of threads waiting for writelocks, the order, relative to one another, in which they receive the writelock is unspecified. For threads waiting to obtain readlocks, the read/write mutex supports only the Unspecified intraclass scheduling policy. That is, given a set of threads waiting for readlocks, the order, relative to one another, in which they receive the readlock is unspecified. 3.2.3. Mutex Concepts
3.2.3.1. ReadWriteMutex Concept
A ReadWriteMutex object has three states: readlocked, writelocked, and unlocked. ReadWriteMutex object state can only be determined by a lock object meeting the appropriate lock concept requirements and constructed for the ReadWriteMutex object. A ReadWriteMutex is NonCopyable. For a ReadWriteMutex type M, and an object m of that type, the following expressions must be wellformed and have the indicated effects.
Effects Constructs a read/write mutex object m. Postcondition: m is unlocked. Precondition: m is unlocked. Destroys a read/write mutex object m. A type meeting the ScopedReadWriteLock requirements. A type meeting the ScopedLock requirements. A type meeting the ScopedLock requirements.
A TryReadWriteMutex is a refinement of ReadWriteMutex. For a TryReadWriteMutex type M and an object m of that type, the following expressions must be wellformed and have the indicated effects.
Table 9.13. TryReadWriteMutex Expressions Expression M::scoped_try_read_write_lock M::scoped_try_read_lock M::scoped_try_write_lock Effects A type meeting the ScopedTryReadWriteLock requirements. A type meeting the ScopedTryLock requirements. A type meeting the ScopedTryLock requirements.
267
Chapter 9. Boost.Threads
3.2.3.3. TimedReadWriteMutex Concept
A TimedReadWriteMutex is a refinement of TryReadWriteMutex. For a TimedReadWriteMutex type M and an object m of that type the following expressions must be wellformed and have the indicated effects.
Table 9.14. TimedReadWriteMutex Expressions Expression M::scoped_timed_read_write_lock M::scoped_timed_read_lock M::scoped_timed_write_lock 3.2.4. Mutex Models Boost.Threads currently supplies three models of ReadWriteMutex and its refinements. Effects A type meeting the ScopedTimedReadWriteLock requirements. A type meeting the ScopedTimedLock requirements. A type meeting the ScopedTimedLock requirements.
Table 9.15. Mutex Models Concept ReadWriteMutex TryReadWriteMutex TimedReadWriteMutex 3.2.5. Lock Concepts A read/write lock object provides a safe means for locking and unlocking a read/write mutex object (an object whose type is a model of ReadWriteMutex or one of its refinements). In other words they are an implementation of the Scoped Locking[SchmidtStalRohnertBuschmann] pattern. The ScopedReadWriteLock, ScopedTryReadWriteLock, and ScopedTimedReadWriteLock concepts formalize the requirements. Read/write lock objects are constructed with a reference to a read/write mutex object and typically acquire ownership of the read/write mutex object by setting its state to locked. They also ensure ownership is relinquished in the destructor. Lock objects also expose functions to query the lock status and to manually lock and unlock the read/write mutex object. Read/write lock objects are meant to be short lived, expected to be used at block scope only. The read/write lock objects are not threadsafe. Read/write lock objects must maintain state to indicate whether or not they've been locked and this state is not protected by any synchronization concepts. For this reason a read/write lock object should never be shared between multiple threads.
3.2.5.1. ReadWriteLock Concept
Refines
Models boost::read_write_mutex
ReadWriteMutex TryReadWriteMutex
boost::try_read_write_mutex boost::timed_read_write_mutex
For a read/write lock type L and an object lk and const object clk of that type, the following expressions must be wellformed and have the indicated effects.
Chapter 9. Boost.Threads
if (locked()) unlock(); Returns type void*, nonzero if the associated read/write mutex object has been either readlocked or writelocked by clk, otherwise 0. Returns a bool, (&clk)>operator const void*() != 0 Returns an enumeration constant of type read_write_lock_state: read_write_lock_state::read_locked if the associated read/write mutex object has been readlocked by clk, read_write_lock_state::write_locked if it has been writelocked by clk, and read_write_lock_state::unlocked if has not been locked by clk. Returns a bool, (&clk)>state() == read_write_lock_state::read_locked. Returns a bool, (&clk)>state() == read_write_lock_state::write_locked. Throws boost::lock_error if locked(). If the associated read/write mutex object is already readlocked by some other thread, the effect depends on the interclass scheduling policy of the associated read/write mutex: either immediately obtains an additional readlock on the associated read/write mutex, or places the current thread in the Blocked state until the associated read/write mutex is unlocked, after which the current thread is placed in the Ready state, eventually to be returned to the Running state.
clk.state()
clk.read_locked() clk.write_locked()
lk.read_lock()
If the associated read/write mutex object is already writelocked by some other thread, places the current thread in the Blocked state until the associated read/write mutex is unlocked, after which the current thread is placed in the Ready state, eventually to be returned to the Running state. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Postcondition: state() == read_write_lock_state::read_locked Throws boost::lock_error if locked(). If the associated read/write mutex object is already locked by some other thread, places the current thread in the Blocked state until the associated read/write mutex is unlocked, after which the current thread is placed in the Ready state, eventually to be returned to the Running state. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Postcondition: state() == read_write_lock_state::write_locked Throws boost::lock_error if state() != read_write_lock_state::write_locked.
lk.write_lock()
lk.demote()
Converts the lock held on the associated read/write mutex object from a writelock to a readlock without releasing the lock. Postcondition: state() == read_write_lock_state::read_locked
269
Chapter 9. Boost.Threads
lk.promote()
Throws boost::lock_error if state() != read_write_lock_state::read_locked or if the lock cannot be promoted because another lock on the same mutex is already waiting to be promoted. Makes a blocking attempt to convert the lock held on the associated read/write mutex object from a readlock to a writelock without releasing the lock. Throws boost::lock_error if !locked().
lk.unlock()
A ScopedReadWriteLock is a refinement of ReadWriteLock. For a ScopedReadWriteLock type L and an object lk of that type, and an object m of a type meeting the ReadWriteMutex requirements, and an object s of type read_write_lock_state, the following expressions must be wellformed and have the indicated effects.
Table 9.17. ScopedReadWriteLock Expressions Expression L lk(m,s); Effects Constructs an object lk and associates read/write mutex object m with it, then: if s == read_write_lock_state::read_locked, calls read_lock(); if s==read_write_lock_state::write_locked, calls write_lock().
A TryReadWriteLock is a refinement of ReadWriteLock. For a TryReadWriteLock type L and an object lk of that type, the following expressions must be wellformed and have the indicated effects.
Table 9.18. TryReadWriteLock Expressions Expression Throws boost::lock_error if locked(). lk.try_read_lock() Makes a nonblocking attempt to readlock the associated read/write mutex object, returning true if the attempt is successful, otherwise false. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Throws boost::lock_error if locked(). lk.try_write_lock() Makes a nonblocking attempt to writelock the associated read/write mutex object, returning true if the attempt is successful, otherwise false. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Throws boost::lock_error if state() != read_write_lock_state::write_locked. Effects
lk.try_demote()
270
Chapter 9. Boost.Threads
Makes a nonblocking attempt to convert the lock held on the associated read/write mutex object from a writelock to a readlock without releasing the lock, returning true if the attempt is successful, otherwise false. Throws boost::lock_error if state() != read_write_lock_state::read_locked. lk.try_promote() Makes a nonblocking attempt to convert the lock held on the associated read/write mutex object from a readlock to a writelock without releasing the lock, returning true if the attempt is successful, otherwise false.
A ScopedTryReadWriteLock is a refinement of TryReadWriteLock. For a ScopedTryReadWriteLock type L and an object lk of that type, and an object m of a type meeting the TryReadWriteMutex requirements, and an object s of type read_write_lock_state, and an object b of type blocking_mode, the following expressions must be wellformed and have the indicated effects.
Table 9.19. ScopedTryReadWriteLock Expressions Expression L lk(m,s,b); Effects Constructs an object lk and associates read/write mutex object m with it, then: if s == read_write_lock_state::read_locked, calls read_lock() if b, otherwise try_read_lock(); if s==read_write_lock_state::write_locked, calls write_lock() if b, otherwise try_write_lock.
A TimedReadWriteLock is a refinement of TryReadWriteLock. For a TimedReadWriteLock type L and an object lk of that type, and an object t of type boost::xtime, the following expressions must be wellformed and have the indicated effects.
Table 9.20. TimedReadWriteLock Expressions Expression Throws boost::lock_error if locked(). lk.timed_read_lock(t) Makes a blocking attempt to readlock the associated read/write mutex object, and returns true if successful within the specified time t, otherwise false. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Throws boost::lock_error if locked(). lk.timed_write_lock(t) Makes a blocking attempt to writelock the associated read/write mutex object, and returns true if successful within the specified time t, otherwise false. If the associated read/write mutex object is already locked by the same thread the behavior is dependent on the locking strategy of the associated read/write mutex object. Throws boost::lock_error if state() != read_write_lock_state::write_locked. Effects
lk.timed_demote(t)
271
Chapter 9. Boost.Threads
Makes a blocking attempt to convert the lock held on the associated read/write mutex object from a writelock to a readlock without releasing the lock, returning true if the attempt is successful in the specified time t, otherwise false. Throws boost::lock_error if state() != read_write_lock_state::read_locked. lk.timed_promote(t) Makes a blocking attempt to convert the lock held on the associated read/write mutex object from a readlock to a writelock without releasing the lock, returning true if the attempt is successful in the specified time t, otherwise false.
A ScopedTimedReadWriteLock is a refinement of TimedReadWriteLock. For a ScopedTimedReadWriteLock type L and an object lk of that type, and an object m of a type meeting the TimedReadWriteMutex requirements, and an object s of type read_write_lock_state, and an object t of type boost::xtime, and an object b of type blocking_mode, the following expressions must be wellformed and have the indicated effects.
Table 9.21. ScopedTimedReadWriteLock Expressions Expression L lk(m,s,b); Effects Constructs an object lk and associates read/write mutex object m with it, then: if s == read_write_lock_state::read_locked, calls read_lock() if b, otherwise try_read_lock(); if s==read_write_lock_state::write_locked, calls write_lock() if b, otherwise try_write_lock. Constructs an object lk and associates read/write mutex object m with it, then: if s == read_write_lock_state::read_locked, calls timed_read_lock(t); if s==read_write_lock_state::write_locked, calls timed_write_lock(t).
L lk(m,s,t);
3.2.6. Lock Models Boost.Threads currently supplies six models of ReadWriteLock and its refinements.
Table 9.22. Lock Models Concept ReadWriteLock boost::read_write_mutex::scoped_read_write_lock ScopedReadWriteLock ReadWriteLock boost::try_read_write_mutex::scoped_read_write_lock boost::timed_read_write_mutex::scoped_read_write_lock TryReadWriteLock ScopedTryReadWriteLock TimedReadWriteLock ReadWriteLock boost::try_read_write_mutex::scoped_try_read_write_lock TryReadWriteLock boost::timed_read_write_mutex::scoped_try_read_write_lock TryReadWriteLock Refines Models
272
Chapter 9. Boost.Threads
ScopedTimedReadWriteLock
TimedReadWriteLock
boost::timed_read_write_mutex::scoped_timed_read_write_lock
4. Rationale
This page explains the rationale behind various design decisions in the Boost.Threads library. Having the rationale documented here should explain how we arrived at the current design as well as prevent future rehashing of discussions and thought processes that have already occurred. It can also give users a lot of insight into the design process required for this library.
273
Chapter 9. Boost.Threads
A lock object is not a synchronization primitive. A lock object's sole responsibility is to ensure that a mutex is both locked and unlocked in a manner that won't result in the common error of locking a mutex and then forgetting to unlock it. This means that instances of a lock object are only going to be created, at least in theory, within block scope and won't be shared between threads. Only the mutex objects will be created outside of block scope and/or shared between threads. Though it's possible to create a lock object outside of block scope and to share it between threads, to do so would not be a typical usage (in fact, to do so would likely be an error). Nor are there any cases when such usage would be required. Lock objects must maintain some state information. In order to allow a program to determine if a try_lock or timed_lock was successful the lock object must retain state indicating the success or failure of the call made in its constructor. If a lock object were to have such state and remain threadsafe it would need to synchronize access to the state information which would result in roughly doubling the time of most operations. Worse, since checking the state can occur only by a call after construction, we'd have a race condition if the lock object were shared between threads. So, to avoid the overhead of synchronizing access to the state information and to avoid the race condition, the Boost.Threads library simply does nothing to make lock objects threadsafe. Instead, sharing a lock object between threads results in undefined behavior. Since the only proper usage of lock objects is within block scope this isn't a problem, and so long as the lock object is properly used there's no danger of any multithreading issues.
274
Chapter 9. Boost.Threads
4.4.4. 4. Use case: Creation of several threads in a loop which are later joined.
void foo() { for (int i=0; i<NUM_THREADS; ++i) threads[i] = create_thread(&bar); for (int i=0; i<NUM_THREADS; ++i) threads[i].join(); }
4.4.5. 5. Use case: Creation of a thread whose ownership is passed to another object/method.
void foo() { thread = create_thread(&bar); manager.owns(thread); }
4.4.6. 6. Use case: Creation of a thread whose ownership is shared between multiple objects.
void foo() { thread = create_thread(&bar); manager1.add(thread); manager2.add(thread); }
Of these usage patterns there's only one that requires reference management (number 6). Hopefully it's fairly obvious that this usage pattern simply won't occur as often as the other usage patterns. So there really isn't a "typical need" for a thread concept, though there is some need. Since the need isn't typical we must use different criteria for deciding on either a thread_ref or thread design. Possible criteria include ease of use and performance. So let's analyze both of these carefully. With ease of use we can look at existing experience. The standard C++ objects that represent a system resource, such as std::iostream, are noncopyable, so we know that C++ programmers must at least be experienced with this design. Most C++ developers are also used to smart pointers such as boost::shared_ptr, so we know they can at least adapt to a thread_ref concept with little effort. So existing experience isn't going to lead us to a choice. The other thing we can look at is how difficult it is to use both types for the six usage patterns above. If we find it overly difficult to use a concept for any of the usage patterns there would be a good argument for choosing the other design. So we'll
275
Chapter 9. Boost.Threads
code all six usage patterns using both designs. 4.4.7. 1. Comparison: simple creation of a thread.
void foo() { thread thrd(&bar); } void foo() { thread_ref thrd = create_thread(&bar); }
4.4.10. 4. Comparison: creation of several threads in a loop which are later joined.
void foo() { std::auto_ptr<thread> threads[NUM_THREADS]; for (int i=0; i<NUM_THREADS; ++i) threads[i] = std::auto_ptr<thread>(new thread(&bar)); for (int i= 0; i<NUM_THREADS; ++i)threads[i]>join(); } void foo() { thread_ref threads[NUM_THREADS]; for (int i=0; i<NUM_THREADS; ++i) threads[i] = create_thread(&bar); for (int i= 0; i<NUM_THREADS; ++i)threads[i]>join(); }
276
Chapter 9. Boost.Threads
4.4.12. 6. Comparison: creation of a thread whose ownership is shared between multiple objects.
void foo() { boost::shared_ptr<thread> thrd(new thread(&bar)); manager1.add(thrd); manager2.add(thrd); } void foo() { thread_ref thrd = create_thread(&bar); manager1.add(thrd); manager2.add(thrd); }
This shows the usage patterns being nearly identical in complexity for both designs. The only actual added complexity occurs because of the use of operator new in (4), (5), and (6); and the use of std::auto_ptr and boost::shared_ptr in (4) and (6) respectively. However, that's not really much added complexity, and C++ programmers are used to using these idioms anyway. Some may dislike the presence of operator new in user code, but this can be eliminated by proper design of higher level concepts, such as the boost::thread_group class that simplifies example (4) down to:
void foo() { thread_group threads; for (int i=0; i<NUM_THREADS; ++i) threads.create_thread(&bar); threads.join_all(); }
So ease of use is really a wash and not much help in picking a design. So what about performance? Looking at the above code examples, we can analyze the theoretical impact to performance that both designs have. For (1) we can see that platforms that don't have a refcounted native thread type (POSIX, for instance) will be impacted by a thread_ref design. Even if the native thread type is refcounted there may be an impact if more state information has to be maintained for concepts foreign to the native API, such as clean up stacks for Win32 implementations. For (2) and (3) the performance impact will be identical to (1). For (4) things get a little more interesting and we find that theoretically at least the thread_ref may perform faster since the thread design requires dynamic memory allocation/deallocation. However, in practice there may be dynamic allocation for the thread_ref design as well, it will just be hidden from the user. As long as the implementation has to do dynamic allocations the thread_ref loses again because of the reference management. For (5) we see the same impact as we do for (4). For (6) we still have a possible impact to the thread design because of dynamic allocation but thread_ref no longer suffers because of its reference management, and in fact, theoretically at least, the thread_ref may do a better job of managing the references. All of this indicates that thread wins for (1), (2) and (3); with (4) and (5) the winner depending on the implementation and the platform but with the thread design probably having a better chance; and with (6) it will again depend on the implementation and platform but this time we favor thread_ref slightly. Given all of this it's a narrow margin, but the thread design prevails.
277
Chapter 9. Boost.Threads
Given this analysis, and the fact that noncopyable objects for system resources are the normal designs that C++ programmers are used to dealing with, the Boost.Threads library has gone with a noncopyable design.
5. Reference
5.1. Header <boost/thread/barrier.hpp>
namespace boost { class barrier; }
Class barrier boost::barrier An object of class barrier is a synchronization primitive used to cause a set of threads to wait until they each perform a certain function or each reach a particular point in their execution.
Synopsis class barrier : private boost::noncopyable { public: // construct/copy/destruct barrier(size_t); ~barrier(); // Exposition only
278
Chapter 9. Boost.Threads
// waiting bool wait(); };
Description
When a barrier is created, it is initialized with a thread count N. The first N1 calls to wait() will all cause their threads to be blocked. The Nth call to wait() will allow all of the waiting threads, including the Nth thread, to be placed in a ready state. The Nth call will also "reset" the barrier such that, if an additional N+1th call is made to wait(), it will be as though this were the first call to wait(); in other words, the N+1th to 2N1th calls to wait() will cause their threads to be blocked, and the 2Nth call to wait() will allow all of the waiting threads, including the 2Nth thread, to be placed in a ready state and reset the barrier. This functionality allows the same set of N threads to reuse a barrier object to synchronize their execution at multiple points during their execution. See Glossary for definitions of thread states blocked and ready. Note that "waiting" is a synonym for blocked.
barrier construct/copy/destruct
1. barrier(size_t count); Effects Constructs a barrier object that will cause count threads to block on a call to wait(). 2. ~barrier(); Effects Destroys *this. If threads are still executing their wait() operations, the behavior for these threads is undefined.
barrier waiting
1. bool wait(); Effects Wait until N threads call wait(), where N equals the count provided to the constructor for the barrier object. Note that if the barrier is destroyed before wait() can return, the behavior is undefined. Returns Exactly one of the N threads will receive a return value of true, the others will receive a value of false. Precisely which thread receives the return value of true will be implementationdefined. Applications can use this value to designate one thread as a leader that will take a certain action, and the other threads emerging from the barrier can wait for that action to take place.
279
Chapter 9. Boost.Threads
An object of class condition is a synchronization primitive used to cause a thread to wait until a particular shareddata condition (or time) is met.
Synopsis class condition : private boost::noncopyable { public: // construct/copy/destruct condition(); ~condition(); // notification void notify_one(); void notify_all(); // waiting template<typename ScopedLock> void wait(ScopedLock&); template<typename ScopedLock, typename Pred> void wait(ScopedLock&, Pred); template<typename ScopedLock> bool timed_wait(ScopedLock&, const boost::xtime&); template<typename ScopedLock, typename Pred> bool timed_wait(ScopedLock&, Pred); }; // Exposition only
Description
A condition object is always used in conjunction with a mutex object (an object whose type is a model of a Mutex or one of its refinements). The mutex object must be locked prior to waiting on the condition, which is verified by passing a lock object (an object whose type is a model of Lock or one of its refinements) to the condition object's wait functions. Upon blocking on the condition object, the thread unlocks the mutex object. When the thread returns from a call to one of the condition object's wait functions the mutex object is again locked. The tricky unlock/lock sequence is performed automatically by the condition object's wait functions. The condition type is often used to implement the Monitor Object and other important patterns (see [SchmidtStalRohnertBuschmann] and [Hoare74]). Monitors are one of the most important patterns for creating reliable multithreaded programs. See Glossary for definitions of thread states blocked and ready. Note that "waiting" is a synonym for blocked.
condition construct/copy/destruct
condition notification
1. void notify_one(); Effects If there is a thread waiting on *this, change that thread's state to ready. Otherwise there is no effect. Notes
280
Chapter 9. Boost.Threads
If more than one thread is waiting on *this, it is unspecified which is made ready. After returning to a ready state the notified thread must still acquire the mutex again (which occurs within the call to one of the condition object's wait functions.) 2. void notify_all(); Effects Change the state of all threads waiting on *this to ready. If there are no waiting threads, notify_all() has no effect.
condition waiting
1. template<typename ScopedLock> void wait(ScopedLock& lock); Requires ScopedLock meets the ScopedLock requirements. Effects Releases the lock on the mutex object associated with lock, blocks the current thread of execution until readied by a call to this>notify_one() or this>notify_all(), and then reacquires the lock. Throws lock_error if !lock.locked() 2. template<typename ScopedLock, typename Pred>
void wait(ScopedLock& lock, Pred pred);
Requires ScopedLock meets the ScopedLock requirements and the return from pred() is convertible to bool. Effects As if: while (!pred()) wait(lock) Throws lock_error if !lock.locked() 3. template<typename ScopedLock>
bool timed_wait(ScopedLock& lock, const boost::xtime& xt);
Requires ScopedLock meets the ScopedLock requirements. Effects Releases the lock on the mutex object associated with lock, blocks the current thread of execution until readied by a call to this>notify_one() or this>notify_all(), or until time xt is reached, and then reacquires the lock. Returns false if time xt is reached, otherwise true. Throws lock_error if !lock.locked() 4. template<typename ScopedLock, typename Pred>
bool timed_wait(ScopedLock& lock, Pred pred);
Requires ScopedLock meets the ScopedLock requirements and the return from pred() is convertible to bool. Effects As if: while (!pred()) { if (!timed_wait(lock, xt)) return false; } return true; Returns false if xt is reached, otherwise true. Throws lock_error if !lock.locked()
281
Chapter 9. Boost.Threads
Class lock_error boost::lock_error The lock_error class defines an exception type thrown to indicate a locking related error has been detected.
Synopsis class lock_error : public std::logical_error { public: // construct/copy/destruct lock_error(); };
Description
Examples of errors indicated by a lock_error exception include a lock operation which can be determined to result in a deadlock, or unlock operations attempted by a thread that does not own the lock.
lock_error construct/copy/destruct
Class thread_resource_error boost::thread_resource_error The thread_resource_error class defines an exception type that is thrown by constructors in the Boost.Threads library when threadrelated resources can not be acquired.
Synopsis class thread_resource_error : public std::runtime_error { public: // construct/copy/destruct thread_resource_error(); };
Description
thread_resource_error is used only when threadrelated resources cannot be acquired; memory allocation failures are indicated by std::bad_alloc.
282
Chapter 9. Boost.Threads
thread_resource_error construct/copy/destruct
Class mutex boost::mutex The mutex class is a model of the Mutex concept.
Synopsis class mutex : private boost::noncopyable // Exposition only { public: // types typedef implementationdefined scoped_lock; // construct/copy/destruct mutex(); ~mutex(); };
Description
The mutex class is a model of the Mutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see try_mutex and timed_mutex. For Recursive locking mechanics, see recursive_mutex, recursive_try_mutex, and recursive_timed_mutex. The mutex class supplies the following typedef, which models the specified locking strategy: Lock Name scoped_lock Lock Concept ScopedLock
The mutex class uses an Unspecified locking strategy, so attempts to recursively lock a mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all mutex models in Boost.Threads, mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
283
Chapter 9. Boost.Threads
mutex construct/copy/destruct
1. mutex(); Effects Constructs a mutex object. Postconditions *this is in an unlocked state. 2. ~mutex(); Effects Destroys a mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Class try_mutex boost::try_mutex The try_mutex class is a model of the TryMutex concept.
Synopsis class try_mutex : private boost::noncopyable // Exposition only { public: // types typedef implementationdefined scoped_lock; typedef implementationdefined scoped_try_lock; // construct/copy/destruct try_mutex(); ~try_mutex(); };
Description
The try_mutex class is a model of the TryMutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see mutex and timed_mutex. For Recursive locking mechanics, see recursive_mutex, recursive_try_mutex, and recursive_timed_mutex. The try_mutex class supplies the following typedefs, which model the specified locking strategies: Lock Name scoped_lock scoped_try_lock Lock Concept ScopedLock ScopedTryLock
The try_mutex class uses an Unspecified locking strategy, so attempts to recursively lock a try_mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as
284
Chapter 9. Boost.Threads
efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all mutex models in Boost.Threads, try_mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
try_mutex construct/copy/destruct
1. try_mutex(); Effects Constructs a try_mutex object. Postconditions *this is in an unlocked state. 2. ~try_mutex(); Effects Destroys a try_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Class timed_mutex boost::timed_mutex The timed_mutex class is a model of the TimedMutex concept.
Synopsis class timed_mutex : private boost::noncopyable // Exposition only { public: // types typedef implementationdefined scoped_lock; typedef implementationdefined scoped_try_lock; typedef implementationdefined scoped_timed_lock; // construct/copy/destruct timed_mutex(); ~timed_mutex(); };
Description
The timed_mutex class is a model of the TimedMutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see mutex and try_mutex. For Recursive locking mechanics, see recursive_mutex, recursive_try_mutex, and recursive_timed_mutex. The timed_mutex class supplies the following typedefs, which model the specified locking strategies:
285
Chapter 9. Boost.Threads
The timed_mutex class uses an Unspecified locking strategy, so attempts to recursively lock a timed_mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all mutex models in Boost.Threads, timed_mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
timed_mutex construct/copy/destruct
1. timed_mutex(); Effects Constructs a timed_mutex object. Postconditions *this is in an unlocked state. 2. ~timed_mutex(); Effects Destroys a timed_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Macro BOOST_ONCE_INIT BOOST_ONCE_INIT The call_once function and once_flag type (statically initialized to BOOST_ONCE_INIT) can be used to run a routine exactly once. This can be used to initialize data in a threadsafe manner.
286
Chapter 9. Boost.Threads
Synopsis BOOST_ONCE_INIT
Description
The implementationdefined macro BOOST_ONCE_INIT is a constant value used to initialize once_flag instances to indicate that the logically associated routine has not been run yet. See call_once for more details. Function call_once boost::call_once The call_once function and once_flag type (statically initialized to BOOST_ONCE_INIT) can be used to run a routine exactly once. This can be used to initialize data in a threadsafe manner.
Synopsis call_once(void (*func)() func, once_flag& flag);
Description
Requires The function func shall not throw exceptions. Effects As if (in an atomic fashion): if (flag == BOOST_ONCE_INIT) func(); Postconditions flag != BOOST_ONCE_INIT
Class recursive_mutex boost::recursive_mutex The recursive_mutex class is a model of the Mutex concept.
287
Chapter 9. Boost.Threads
Synopsis class recursive_mutex : private boost::noncopyable { public: // types typedef implementationdefined scoped_lock; // construct/copy/destruct recursive_mutex(); ~recursive_mutex(); }; // Exposition only
Description
The recursive_mutex class is a model of the Mutex concept. It should be used to synchronize access to shared resources using Recursive locking mechanics. For classes that model related mutex concepts, see recursive_try_mutex and recursive_timed_mutex. For Unspecified locking mechanics, see mutex, try_mutex, and timed_mutex. The recursive_mutex class supplies the following typedef, which models the specified locking strategy:
Table 9.23. Supported Lock Types Lock Name scoped_lock Lock Concept ScopedLock
The recursive_mutex class uses a Recursive locking strategy, so attempts to recursively lock a recursive_mutex object succeed and an internal "lock count" is maintained. Attempts to unlock a recursive_mutex object by threads that don't own a lock on it result in undefined behavior. Like all mutex models in Boost.Threads, recursive_mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
recursive_mutex construct/copy/destruct
1. recursive_mutex(); Effects Constructs a recursive_mutex object. Postconditions *this is in an unlocked state. 2. ~recursive_mutex(); Effects Destroys a recursive_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
288
Chapter 9. Boost.Threads
Class recursive_try_mutex boost::recursive_try_mutex The recursive_try_mutex class is a model of the TryMutex concept.
Synopsis class recursive_try_mutex : private boost::noncopyable { public: // types typedef implementationdefined scoped_lock; typedef implementationdefined scoped_try_lock; // construct/copy/destruct recursive_try_mutex(); ~recursive_try_mutex(); }; // Exposition only
Description
The recursive_try_mutex class is a model of the TryMutex concept. It should be used to synchronize access to shared resources using Recursive locking mechanics. For classes that model related mutex concepts, see recursive_mutex and recursive_timed_mutex. For Unspecified locking mechanics, see mutex, try_mutex, and timed_mutex. The recursive_try_mutex class supplies the following typedefs, which model the specified locking strategies:
Table 9.24. Supported Lock Types Lock Name scoped_lock scoped_try_lock Lock Concept ScopedLock ScopedTryLock
The recursive_try_mutex class uses a Recursive locking strategy, so attempts to recursively lock a recursive_try_mutex object succeed and an internal "lock count" is maintained. Attempts to unlock a recursive_mutex object by threads that don't own a lock on it result in undefined behavior. Like all mutex models in Boost.Threads, recursive_try_mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
recursive_try_mutex construct/copy/destruct
1. recursive_try_mutex(); Effects Constructs a recursive_try_mutex object. Postconditions *this is in an unlocked state. 2. ~recursive_try_mutex();
289
Chapter 9. Boost.Threads
Effects Destroys a recursive_try_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Class recursive_timed_mutex boost::recursive_timed_mutex The recursive_timed_mutex class is a model of the TimedMutex concept.
Synopsis class recursive_timed_mutex : private boost::noncopyable { public: // types typedef implementationdefined scoped_lock; typedef implementationdefined scoped_try_lock; typedef implementationdefined scoped_timed_lock; // construct/copy/destruct recursive_timed_mutex(); ~recursive_timed_mutex(); }; // Exposition only
Description
The recursive_timed_mutex class is a model of the TimedMutex concept. It should be used to synchronize access to shared resources using Recursive locking mechanics. For classes that model related mutex concepts, see recursive_mutex and recursive_try_mutex. For Unspecified locking mechanics, see mutex, try_mutex, and timed_mutex. The recursive_timed_mutex class supplies the following typedefs, which model the specified locking strategies:
Table 9.25. Supported Lock Types Lock Name scoped_lock scoped_try_lock scoped_timed_lock Lock Concept ScopedLock ScopedTryLock ScopedTimedLock
The recursive_timed_mutex class uses a Recursive locking strategy, so attempts to recursively lock a recursive_timed_mutex object succeed and an internal "lock count" is maintained. Attempts to unlock a recursive_mutex object by threads that don't own a lock on it result in undefined behavior. Like all mutex models in Boost.Threads, recursive_timed_mutex leaves the scheduling policy as Unspecified. Programmers should make no assumptions about the order in which waiting threads acquire a lock.
290
Chapter 9. Boost.Threads
recursive_timed_mutex construct/copy/destruct
1. recursive_timed_mutex(); Effects Constructs a recursive_timed_mutex object. Postconditions *this is in an unlocked state. 2. ~recursive_timed_mutex(); Effects Destroys a recursive_timed_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Type read_write_scheduling_policy boost::read_write_scheduling_policy::read_write_scheduling_policy Specifies the interclass sheduling policy to use when a set of threads try to obtain different types of locks simultaneously.
Synopsis enum read_write_scheduling_policy { writer_priority, reader_priority, alternating_many_reads, alternating_single_read };
Class read_write_mutex boost::read_write_mutex The read_write_mutex class is a model of the ReadWriteMutex concept.
Synopsis class read_write_mutex : private private { public: // types typedef implementationdefined typedef implementationdefined typedef implementationdefined // construct/copy/destruct boost::noncopyable, boost::noncopyable // Exposition only // Exposition only
291
Chapter 9. Boost.Threads
read_write_mutex(boost::read_write_scheduling_policy); ~read_write_mutex(); };
Description
The read_write_mutex class is a model of the ReadWriteMutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see try_read_write_mutex and timed_read_write_mutex. The read_write_mutex class supplies the following typedefs, which model the specified locking strategies: Lock Name scoped_read_write_lock scoped_read_lock scoped_write_lock Lock Concept ScopedReadWriteLock ScopedLock ScopedLock
The read_write_mutex class uses an Unspecified locking strategy, so attempts to recursively lock a read_write_mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all read/write mutex models in Boost.Threads, read_write_mutex has two types of scheduling policies, an interclass sheduling policy between threads trying to obtain different types of locks and an intraclass sheduling policy between threads trying to obtain the same type of lock. The read_write_mutex class allows the programmer to choose what interclass sheduling policy will be used; however, like all read/write mutex models, read_write_mutex leaves the intraclass sheduling policy as Unspecified.
Note
Selfdeadlock is virtually guaranteed if a thread tries to lock the same read_write_mutex multiple times unless all locks are readlocks (but see below)
read_write_mutex construct/copy/destruct
1. read_write_mutex(boost::read_write_scheduling_policy count); Effects Constructs a read_write_mutex object. Postconditions *this is in an unlocked state. 2. ~read_write_mutex(); Effects Destroys a read_write_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
292
Chapter 9. Boost.Threads
Class try_read_write_mutex boost::try_read_write_mutex The try_read_write_mutex class is a model of the TryReadWriteMutex concept.
Synopsis class try_read_write_mutex : private boost::noncopyable // Exposition only { public: // types typedef implementationdefined scoped_read_write_lock; typedef implementationdefined scoped_try_read_write_lock; typedef implementationdefined scoped_read_lock; typedef implementationdefined scoped_try_read_lock; typedef implementationdefined scoped_write_lock; typedef implementationdefined scoped_try_write_lock; // construct/copy/destruct try_read_write_mutex(boost::read_write_scheduling_policy); ~try_read_write_mutex(); };
Description
The try_read_write_mutex class is a model of the TryReadWriteMutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see read_write_mutex and timed_read_write_mutex. The try_read_write_mutex class supplies the following typedefs, which model the specified locking strategies: Lock Name scoped_read_write_lock scoped_try_read_write_lock scoped_read_lock scoped_try_read_lock scoped_write_lock scoped_try_write_lock Lock Concept ScopedReadWriteLock ScopedTryReadWriteLock ScopedLock ScopedTryLock ScopedLock ScopedTryLock
The try_read_write_mutex class uses an Unspecified locking strategy, so attempts to recursively lock a try_read_write_mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all read/write mutex models in Boost.Threads, try_read_write_mutex has two types of scheduling policies, an interclass sheduling policy between threads trying to obtain different types of locks and an intraclass sheduling policy between threads trying to obtain the same type of lock. The try_read_write_mutex class allows the programmer to choose what interclass sheduling policy will be used; however, like all read/write mutex models, try_read_write_mutex leaves the intraclass sheduling policy as Unspecified.
293
Chapter 9. Boost.Threads
Note
Selfdeadlock is virtually guaranteed if a thread tries to lock the same try_read_write_mutex multiple times unless all locks are readlocks (but see below)
try_read_write_mutex construct/copy/destruct
1. try_read_write_mutex(boost::read_write_scheduling_policy count); Effects Constructs a try_read_write_mutex object. Postconditions *this is in an unlocked state. 2. ~try_read_write_mutex(); Effects Destroys a try_read_write_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
Class timed_read_write_mutex boost::timed_read_write_mutex The timed_read_write_mutex class is a model of the TimedReadWriteMutex concept.
Synopsis class timed_read_write_mutex { public: // types typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined typedef implementationdefined
Description
The timed_read_write_mutex class is a model of the TimedReadWriteMutex concept. It should be used to synchronize access to shared resources using Unspecified locking mechanics. For classes that model related mutex concepts, see read_write_mutex and try_read_write_mutex. The timed_read_write_mutex class supplies the following typedefs, which model the specified locking strategies:
294
Chapter 9. Boost.Threads
Lock Name scoped_read_write_lock scoped_try_read_write_lock scoped_timed_read_write_lock scoped_read_lock scoped_try_read_lock scoped_timed_read_lock scoped_write_lock scoped_try_write_lock scoped_timed_write_lock
Lock Concept ScopedReadWriteLock ScopedTryReadWriteLock ScopedTimedReadWriteLock ScopedLock ScopedTryLock ScopedTimedLock ScopedLock ScopedTryLock ScopedTimedLock
The timed_read_write_mutex class uses an Unspecified locking strategy, so attempts to recursively lock a timed_read_write_mutex object or attempts to unlock one by threads that don't own a lock on it result in undefined behavior. This strategy allows implementations to be as efficient as possible on any given platform. It is, however, recommended that implementations include debugging support to detect misuse when NDEBUG is not defined. Like all read/write mutex models in Boost.Threads, timed_read_write_mutex has two types of scheduling policies, an interclass sheduling policy between threads trying to obtain different types of locks and an intraclass sheduling policy between threads trying to obtain the same type of lock. The timed_read_write_mutex class allows the programmer to choose what interclass sheduling policy will be used; however, like all read/write mutex models, timed_read_write_mutex leaves the intraclass sheduling policy as Unspecified.
Note
Selfdeadlock is virtually guaranteed if a thread tries to lock the same timed_read_write_mutex multiple times unless all locks are readlocks (but see below)
timed_read_write_mutex construct/copy/destruct
1. timed_read_write_mutex(boost::read_write_scheduling_policy count); Effects Constructs a timed_read_write_mutex object. Postconditions *this is in an unlocked state. 2. ~timed_read_write_mutex(); Effects Destroys a timed_read_write_mutex object. Requires *this is in an unlocked state. Notes Danger: Destruction of a locked mutex is a serious programming error resulting in undefined behavior such as a program crash.
295
Chapter 9. Boost.Threads
}
Class thread boost::thread The thread class represents threads of execution, and provides the functionality to create and manage threads within the Boost.Threads library. See Glossary for a precise description of thread of execution, and for definitions of threadingrelated terms and of thread states such as blocked.
Synopsis class thread : private boost::noncopyable // Exposition only { public: // construct/copy/destruct thread(); explicit thread(const boost::function0<void>&); ~thread(); // comparison bool operator==() const; bool operator!=() const; // modifier void join(); // static static void sleep(const xtime&); static void yield(); };
Description
A thread of execution has an initial function. For the program's initial thread, the initial function is main(). For other threads, the initial function is operator() of the function object passed to the thread object's constructor. A thread of execution is said to be "finished" or to have "finished execution" when its initial function returns or is terminated. This includes completion of all thread cleanup handlers, and completion of the normal C++ function return behaviors, such as destruction of automatic storage (stack) objects and releasing any associated implementation resources. A thread object has an associated state which is either "joinable" or "nonjoinable". Except as described below, the policy used by an implementation of Boost.Threads to schedule transitions between thread states is unspecified.
Note
Just as the lifetime of a file may be different from the lifetime of an iostream object which represents the file, the lifetime of a thread of execution may be different from the thread object which represents the thread of execution. In particular, after a call to join(), the thread of execution will no longer exist even though the thread object continues to exist until the end of its normal lifetime. The converse is also possible; if a thread object is destroyed without join() first having been called, the thread of execution continues until its initial function completes.
thread construct/copy/destruct
1. thread();
296
Chapter 9. Boost.Threads
Effects Constructs a thread object representing the current thread of execution. Postconditions *this is nonjoinable. Notes Danger:*this is valid only within the current thread. 2. explicit thread(const boost::function0<void>& threadfunc); Effects Starts a new thread of execution and constructs a thread object representing it. Copies threadfunc (which in turn copies the function object wrapped by threadfunc) to an internal location which persists for the lifetime of the new thread of execution. Calls operator() on the copy of the threadfunc function object in the new thread of execution. Postconditions *this is joinable. Throws boost::thread_resource_error if a new thread of execution cannot be started. 3. ~thread(); Effects Destroys *this. The actual thread of execution may continue to execute after the thread object has been destroyed. Notes If *this is joinable the actual thread of execution becomes "detached". Any resources used by the thread will be reclaimed when the thread of execution completes. To ensure such a thread of execution runs to completion before the thread object is destroyed, call join().
thread comparison
1. bool operator==( rhs) const; Requires The thread is nonterminated or *this is joinable. Returns true if *this and rhs represent the same thread of execution. 2. bool operator!=( rhs) const; Requires The thread is nonterminated or *this is joinable. Returns !(*this==rhs).
thread modifier
1. void join(); Requires *this is joinable. Effects The current thread of execution blocks until the initial function of the thread of execution represented by *this finishes and all resources are reclaimed. Notes If *this == thread() the result is implementationdefined. If the implementation doesn't detect this the result will be deadlock.
297
Chapter 9. Boost.Threads
thread static
1. static void sleep(const xtime& xt); Effects The current thread of execution blocks until xt is reached. 2. static void yield(); Effects The current thread of execution is placed in the ready state. Notes Allow the current thread to give up the rest of its time slice (or other scheduling quota) to another thread. Particularly useful in nonpreemptive implementations.
Class thread_group boost::thread_group The thread_group class provides a container for easy grouping of threads to simplify several common thread creation and management idioms.
Synopsis class thread_group : private boost::noncopyable { public: // construct/copy/destruct thread_group(); ~thread_group(); // Exposition only
// modifier thread* create_thread(const boost::function0<void>&); void add_thread(thread* thrd); void remove_thread(thread* thrd); void join_all(); };
Description
thread_group construct/copy/destruct
1. thread_group(); Effects Constructs an empty thread_group container. 2. ~thread_group(); Effects Destroys each contained thread object. Destroys *this. Notes Behavior is undefined if another thread references *this during the execution of the destructor.
thread_group modifier
298
Chapter 9. Boost.Threads
Creates a new thread object that executes threadfunc and adds it to the thread_group container object's list of managed thread objects. Returns Pointer to the newly created thread object. 2. void add_thread(thread* thrd thrd); Effects Adds thrd to the thread_group object's list of managed thread objects. The thrd object must have been allocated via operator new and will be deleted when the group is destroyed. 3. void remove_thread(thread* thrd thrd); Effects Removes thread from *this's list of managed thread objects. Throws ??? if thrd is not in *this's list of managed thread objects. 4. void join_all(); Effects Calls join() on each of the managed thread objects.
The thread_specific_ptr class defines an interface for using thread specific storage.
Description
Thread specific storage is data associated with individual threads and is often used to make operations that rely on global data threadsafe. Template thread_specific_ptr stores a pointer to an object obtained on a threadbythread basis and calls a specified cleanup handler on the contained pointer when the thread terminates. The cleanup handlers are called in the reverse order of construction of the thread_specific_ptrs, and for the initial thread are called by the destructor, providing the same ordering
299
Chapter 9. Boost.Threads
guarantees as for normal declarations. Each thread initially stores the null pointer in each thread_specific_ptr instance. The template thread_specific_ptr is useful in the following cases: An interface was originally written assuming a single thread of control and it is being ported to a multithreaded environment. Each thread of control invokes sequences of methods that share data that are physically unique for each thread, but must be logically accessed through a globally visible access point instead of being explicitly passed.
thread_specific_ptr construct/copy/destruct
1. thread_specific_ptr(); Requires The expression delete get() is well formed. Effects A threadspecific data key is allocated and visible to all threads in the process. Upon creation, the value NULL will be associated with the new key in all active threads. A cleanup method is registered with the key that will call delete on the value associated with the key for a thread when it exits. When a thread exits, if a key has a registered cleanup method and the thread has a nonNULL value associated with that key, the value of the key is set to NULL and then the cleanup method is called with the previously associated value as its sole argument. The order in which registered cleanup methods are called when a thread exits is undefined. If after all the cleanup methods have been called for all nonNULL values, there are still some nonNULL values with associated cleanup handlers the result is undefined behavior. Throws boost::thread_resource_error if the necessary resources can not be obtained. Notes There may be an implementation specific limit to the number of thread specific storage objects that can be created, and this limit may be small. Rationale The most common need for cleanup will be to call delete on the associated value. If other forms of cleanup are required the overloaded constructor should be called instead. 2. thread_specific_ptr(void (*cleanup)(void*) cleanup); Effects A threadspecific data key is allocated and visible to all threads in the process. Upon creation, the value NULL will be associated with the new key in all active threads. The cleanup method is registered with the key and will be called for a thread with the value associated with the key for that thread when it exits. When a thread exits, if a key has a registered cleanup method and the thread has a nonNULL value associated with that key, the value of the key is set to NULL and then the cleanup method is called with the previously associated value as its sole argument. The order in which registered cleanup methods are called when a thread exits is undefined. If after all the cleanup methods have been called for all nonNULL values, there are still some nonNULL values with associated cleanup handlers the result is undefined behavior. Throws boost::thread_resource_error if the necessary resources can not be obtained. Notes There may be an implementation specific limit to the number of thread specific storage objects that can be created, and this limit may be small. Rationale There is the occasional need to register specialized cleanup methods, or to register no cleanup method at all (done by passing NULL to this constructor. 3. ~thread_specific_ptr(); Effects
300
Chapter 9. Boost.Threads
Deletes the threadspecific data key allocated by the constructor. The threadspecific data values associated with the key need not be NULL. It is the responsibility of the application to perform any cleanup actions for data associated with the key. Notes Does not destroy any data that may be stored in any thread's thread specific storage. For this reason you should not destroy a thread_specific_ptr object until you are certain there are no threads running that have made use of its thread specific storage. Rationale Associated data is not cleaned up because registered cleanup methods need to be run in the thread that allocated the associated data to be guarranteed to work correctly. There's no safe way to inject the call into another thread's execution path, making it impossible to call the cleanup methods safely.
1. T* release(); Postconditions *this holds the null pointer for the current thread. Returns this>get() prior to the call. Rationale This method provides a mechanism for the user to relinquish control of the data associated with the threadspecific key. 2. void reset(T* p = 0); Effects If this>get() != p && this>get() != NULL then call the associated cleanup function. Postconditions *this holds the pointer p for the current thread.
1. T* get() const; Returns The object stored in thread specific storage for the current thread for *this. Notes Each thread initially returns 0. 2. T* operator>() const; Returns this>get(). 3. T& operator*()() const; Requires this>get() != 0 Returns this>get().
301
Chapter 9. Boost.Threads
Type xtime_clock_types boost::xtime_clock_types Specifies the clock type to use when creating an object of type xtime.
Synopsis enum xtime_clock_types { TIME_UTC };
Struct xtime boost::xtime An object of type xtime defines a time that is used to perform highresolution time operations. This is a temporary solution that will be replaced by a more robust time library once available in Boost.
Synopsis struct xtime { platformspecifictype sec; }; // creation int xtime_get(xtime*, int);
Description
The xtime type is used to represent a point on some time scale or a duration in time. This type may be proposed for the C standard by Markus Kuhn. Boost.Threads provides only a very minimal implementation of this proposal; it is expected that a full implementation (or some other time library) will be provided in Boost as a separate library, at which time Boost.Threads will deprecate its own implementation. Note that the resolution is implementation specific. For many implementations the best resolution of time is far more than one nanosecond, and even when the resolution is reasonably good, the latency of a call to xtime_get() may be significant. For maximum portability, avoid durations of less than one second.
xtime creation
1. int xtime_get(xtime* xtp, int clock_type); Postconditions xtp represents the current point in time as a duration since the epoch specified by clock_type. Returns clock_type if successful, otherwise 0.
Chapter 9. Boost.Threads
6.7. How can you lock a Mutex member in a const member function, in order to implement the Monitor Pattern? 6.8. Why supply boost::condition variables rather than event variables? 6.9. Why isn't thread cancellation or termination provided? 6.10. Is it safe for threads to share automatic storage duration (stack) objects via pointers or references? 6.11. Why has class semaphore disappeared? 6.1. Are lock objects thread safe? No! Lock objects are not meant to be shared between threads. They are meant to be shortlived objects created on automatic storage within a code block. Any other usage is just likely to lead to errors and won't really be of actual benefit anyway. Share Mutexes, not Locks. For more information see the rationale behind the design for lock objects. 6.2. Why was Boost.Threads modeled after (specific library name)? It wasn't. Boost.Threads was designed from scratch. Extensive design discussions involved numerous people representing a wide range of experience across many platforms. To ensure portability, the initial implements were done in parallel using POSIX Threads and the Win32 threading API. But the Boost.Threads design is very much in the spirit of C++, and thus doesn't model such C based APIs. 6.3. Why wasn't Boost.Threads modeled after (specific library name)? Existing C++ libraries either seemed dangerous (often failing to take advantage of prior art to reduce errors) or had excessive dependencies on library components unrelated to threading. Existing C libraries couldn't meet our C++ requirements, and were also missing certain features. For instance, the WIN32 thread API lacks condition variables, even though these are critical for the important Monitor pattern [SchmidtStalRohnertBuschmann]. 6.4. Why do Mutexes have noncopyable semantics? To ensure that deadlocks don't occur. The only logical form of copy would be to use some sort of shallow copy semantics in which multiple mutex objects could refer to the same mutex state. This means that if ObjA has a mutex object as part of its state and ObjB is copy constructed from it, then when ObjB::foo() locks the mutex it has effectively locked ObjA as well. This behavior can result in deadlock. Other copy semantics result in similar problems (if you think you can prove this to be wrong then supply us with an alternative and we'll reconsider). 6.5. How can you prevent deadlock from occurring when a thread must lock multiple mutexes? Always lock them in the same order. One easy way of doing this is to use each mutex's address to determine the order in which they are locked. A future Boost.Threads concept may wrap this pattern up in a reusable class. 6.6. Don't noncopyable Mutex semantics mean that a class with a mutex member will be noncopyable as well? No, but what it does mean is that the compiler can't generate a copy constructor and assignment operator, so they will have to be coded explicitly. This is a good thing, however, since the compiler generated operations would not be threadsafe. The following is a simple example of a class with copyable semantics and internal synchronization through a mutex member.
class counter { public: // Doesn't need synchronization since there can be no references to *this // until after it's constructed! explicit counter(int initial_value) : m_value(initial_value) { } // We only need to synchronize other for the same reason we don't have to // synchronize on construction! counter(const counter& other) { boost::mutex::scoped_lock scoped_lock(other.m_mutex); m_value = other.m_value; } // For assignment we need to synchronize both objects! const counter& operator=(const counter& other) { if (this == &other) return *this; boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ? m_mutex : other.m_mutex); boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ? m_mutex : other.m_mutex);
303
Chapter 9. Boost.Threads
m_value = other.m_value; return *this; } int value() const { boost::mutex::scoped_lock scoped_lock(m_mutex); return m_value; } int increment() { boost::mutex::scoped_lock scoped_lock(m_mutex); return ++m_value; } private: mutable boost::mutex m_mutex; int m_value; };
6.7. How can you lock a Mutex member in a const member function, in order to implement the Monitor Pattern? The Monitor Pattern [SchmidtStalRohnertBuschmann] mutex should simply be declared as mutable. See the example code above. The internal state of mutex types could have been made mutable, with all lock calls made via const functions, but this does a poor job of documenting the actual semantics (and in fact would be incorrect since the logical state of a locked mutex clearly differs from the logical state of an unlocked mutex). Declaring a mutex member as mutable clearly documents the intended semantics. 6.8. Why supply boost::condition variables rather than event variables? Condition variables result in user code much less prone to race conditions than event variables. See Section 4.5, Rationale for not providing Event Variables for analysis. Also see [Hoare74] and [SchmidtStalRohnertBuschmann]. 6.9. Why isn't thread cancellation or termination provided? There's a valid need for thread termination, so at some point Boost.Threads probably will include it, but only after we can find a truly safe (and portable) mechanism for this concept. 6.10. Is it safe for threads to share automatic storage duration (stack) objects via pointers or references? Only if you can guarantee that the lifetime of the stack object will not end while other threads might still access the object. Thus the safest practice is to avoid sharing stack objects, particularly in designs where threads are created and destroyed dynamically. Restrict sharing of stack objects to simple designs with very clear and unchanging function and thread lifetimes. (Suggested by Darryl Green). 6.11. Why has class semaphore disappeared? Semaphore was removed as too error prone. The same effect can be achieved with greater safety by the combination of a mutex and a condition variable.
7. Configuration
Boost.Threads uses several configuration macros in <boost/config.hpp>, as well as configuration macros meant to be supplied by the application. These macros are documented here.
Indicates that threading support is available. This means both that there is a platform specific implementation for Boost.Threads and that threading support has been enabled in a platform specific manner. For instance, on the Win32 platform there's an implementation for BOOST_HAS_THREADS Boost.Threads but unless the program is compiled against one of the multithreading runtimes (often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS macro remains undefined.
304
Chapter 9. Boost.Threads
BOOST_HAS_FTIME
BOOST_HAS_GETTTIMEOFDAY
8. Build
How you build the Boost.Threads libraries, and how you build your own applications that use those libraries, are some of the most frequently asked questions. Build processes are difficult to deal with in a portable manner. That's one reason why Boost.Threads makes use of Boost.Build. In general you should refer to the documentation for Boost.Build. This document will only supply you with some simple usage examples for how to use bjam to build and test Boost.Threads. In addition, this document will try to explain the build requirements so that users may create their own build processes (for instance, create an IDE specific project), both for building and testing Boost.Threads, as well as for building their own projects using Boost.Threads.
This will create the debug and the release builds of the Boost.Threads library.
Note
Invoking the above command in boost_root will build all of the Boost distribution, including Boost.Threads. The Jamfile supplied with Boost.Threads produces a dynamic link library named boost_thread{buildspecifictags}.{extension}, where the buildspecific tags indicate the toolset used to build the library, whether it's a debug or release build, what version of Boost was used, etc.; and the extension is the appropriate extension for a dynamic link library for the platform for which Boost.Threads is being built. For instance, a debug library built for Win32 with VC++ 7.1 using Boost 1.31 would be named boost_threadvc71mtgd1_31.dll. The source files that are used to create the Boost.Threads library are all of the *.cpp files found in boost_root/libs/thread/src. These need to be built with the compiler's and linker's multithreading support enabled. If you want to create your own build solution you'll have to follow these same guidelines. One of the most frequently reported problems when trying to do this occurs from not enabling the compiler's and linker's support for multithreading.
Chapter 9. Boost.Threads
bjam sTOOLS=toolset test
9. Implementation Notes
9.1. Win32
In the current Win32 implementation, creating a boost::thread object during dll initialization will result in deadlock because the thread class constructor causes the current thread to wait on the thread that is being created until it signals that it has finished its initialization, and, as stated in the MSDN Library, "DllMain" article, "Remarks" section, "Because DLL notifications are serialized, entrypoint functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result." (Also see "Under the Hood", January 1996 for a more detailed discussion of this issue). The following nonexhaustive list details some of the situations that should be avoided until this issue can be addressed: Creating a boost::thread object in DllMain() or in any function called by it. Creating a boost::thread object in the constructor of a global static object or in any function called by one. Creating a boost::thread object in MFC's CWinApp::InitInstance() function or in any function called by it. Creating a boost::thread object in the function pointed to by MFC's _pRawDllMain function pointer or in any function called by it.
Chapter 9. Boost.Threads
comments in that file for more information. 10.1.3. Barrier functionality added A new class, boost::barrier, was added. 10.1.4. Read/write mutex functionality added New classes, boost::read_write_mutex, boost::try_read_write_mutex, and boost::timed_read_write_mutex were added.
Note
Since the read/write mutex and related classes are new, both interface and implementation are liable to change in future releases of Boost.Threads. The lock concepts and lock promotion in particular are still under discussion and very likely to change. 10.1.5. Threadspecific pointer functionality changed The boost::thread_specific_ptr constructor now takes an optional pointer to a cleanup function that is called to release the threadspecific data that is being pointed to by boost::thread_specific_ptr objects. Fixed: the number of available threadspecific storage "slots" is too small on some platforms. Fixed: thread_specific_ptr::reset() doesn't check error returned by tss::set() (the tss::set() function now throws if it fails instead of returning an error code). Fixed: calling boost::thread_specific_ptr::reset() or boost::thread_specific_ptr::release() causes doubledelete: once when boost::thread_specific_ptr::reset() or boost::thread_specific_ptr::release() is called and once when boost::thread_specific_ptr::~thread_specific_ptr() is called. 10.1.6. Mutex implementation changed for Win32 On Win32, boost::mutex, boost::try_mutex, boost::recursive_mutex, and boost::recursive_try_mutex now use a Win32 critical section whenever possible; otherwise they use a Win32 mutex. As before, boost::timed_mutex and boost::recursive_timed_mutex use a Win32 mutex. 10.1.7. Windows CE support improved Minor changes were made to make Boost.Threads work on Windows CE.
Glossary
Definitions are given in terms of the C++ Standard [ISO98]. References to the standard are in the form [1.2.3/4], which represents the section number, with the paragraph number following the "/". Because the definitions are written in something akin to "standardese", they can be difficult to understand. The intent isn't to confuse, but rather to clarify the additional requirements Boost.Threads places on a C++ implementation as defined by the C++ Standard. Thread Thread is short for "thread of execution". A thread of execution is an execution environment [1.9/7] within the execution environment of a C++ program [1.9]. The main() function [3.6.1] of the program is the initial function of the initial thread. A program in a multithreading environment always has an initial thread even if the program explicitly creates no additional threads. Unless otherwise specified, each thread shares all aspects of its execution environment with other threads in the program. Shared aspects of the execution environment include, but are not limited to, the following:
307
Chapter 9. Boost.Threads
Static storage duration (static, extern) objects [3.7.1]. Dynamic storage duration (heap) objects [3.7.3]. Thus each memory allocation will return a unique addresses, regardless of the thread making the allocation request. Automatic storage duration (stack) objects [3.7.2] accessed via pointer or reference from another thread. Resources provided by the operating system. For example, files. The program itself. In other words, each thread is executing some function of the same program, not a totally different program. Each thread has its own: Registers and current execution sequence (program counter) [1.9/5]. Automatic storage duration (stack) objects [3.7.2]. Threadsafe A program is threadsafe if it has no race conditions, does not deadlock, and has no priority failures. Note that threadsafety does not necessarily imply efficiency, and than while some threadsafety violations can be determined statically at compile time, many threadsafety errors can only only be detected at runtime. Thread State During the lifetime of a thread, it shall be in one of the following states:
Table 9.26. Thread States State Ready Running Blocked Description Ready to run, but waiting for a processor. Currently executing on a processor. Zero or more threads may be running at any time, with a maximum equal to the number of processors. Waiting for some resource other than a processor which is not currently available, or for the completion of calls to library functions [1.9/6]. The term "waiting" is synonymous with "blocked"
Terminated Finished execution but not yet detached or joined. Thread state transitions shall occur only as specified:
Table 9.27. Thread States Transitions From [none] Ready Running Running To Ready Running Ready Blocked Cause Thread is created by a call to a library function. In the case of the initial thread, creation is implicit and occurs during the startup of the main() function [3.6.1]. Processor becomes available. Thread preempted. Thread calls a library function which waits for a resource or for the completion of I/O. Thread returns from its initial function, calls a thread termination library function, or is canceled by some other thread calling a thread termination library function. The resource being waited for becomes available, or the blocking library function completes.
308
Running
Terminated
Blocked
Ready
Chapter 9. Boost.Threads
Terminated
[none]
Thread is detached or joined by some other thread calling the appropriate library function, or by program termination [3.6.3].
[Note: if a suspend() function is added to the threading library, additional transitions to the blocked state will have to be added to the above table.] Race Condition A race condition is what occurs when multiple threads read from and write to the same memory without proper synchronization, resulting in an incorrect value being read or written. The result of a race condition may be a bit pattern which isn't even a valid value for the data type. A race condition results in undefined behavior [1.3.12]. Race conditions can be prevented by serializing memory access using the tools provided by Boost.Threads. Deadlock Deadlock is an execution state where for some set of threads, each thread in the set is blocked waiting for some action by one of the other threads in the set. Since each is waiting on the others, none will ever become ready again. Starvation The condition in which a thread is not making sufficient progress in its work during a given time interval. Priority Failure A priority failure (such as priority inversion or infinite overtaking) occurs when threads are executed in such a sequence that required work is not performed in time to be useful. Undefined Behavior The result of certain operations in Boost.Threads is undefined; this means that those operations can invoke almost any behavior when they are executed. An operation whose behavior is undefined can work "correctly" in some implementations (i.e., do what the programmer thought it would do), while in other implementations it may exhibit almost any "incorrect" behaviorsuch as returning an invalid value, throwing an exception, generating an access violation, or terminating the process. Executing a statement whose behavior is undefined is a programming error. Memory Visibility An address [1.7] shall always point to the same memory byte, regardless of the thread or processor dereferencing the address. An object [1.8, 1.9] is accessible from multiple threads if it is of static storage duration (static, extern) [3.7.1], or if a pointer or reference to it is explicitly or implicitly dereferenced in multiple threads. For an object accessible from multiple threads, the value of the object accessed from one thread may be indeterminate or different from the value accessed from another thread, except under the conditions specified in the following table. For the same row of the table, the value of an object accessible at the indicated sequence point in thread A will be determinate and the same if accessed at or after the indicated sequence point in thread B, provided the object is not otherwise modified. In the table, the "sequence point at a call" is the sequence point after the evaluation of all function arguments [1.9/17], while the "sequence point after a call" is the sequence point after the copying of the returned value... [1.9/17].
Table 9.28. Memory Visibility Thread A The sequence point at a call to a library threadcreation function. The sequence point at a call to a library function which locks a mutex, directly or by waiting for a condition variable. Thread B The first sequence point of the initial function in the new thread created by the Thread A call. The sequence point after a call to a library function which unlocks the same mutex.
309
Chapter 9. Boost.Threads
The last sequence point before thread termination. The sequence point at a call to a library function which signals or broadcasts a condition variable.
The sequence point after a call to a library function which joins the terminated thread. The sequence point after the call to the library function which was waiting on that same condition variable or signal.
The architecture of the execution environment and the observable behavior of the abstract machine [1.9] shall be the same on all processors. The latitude granted by the C++ standard for an implementation to alter the definition of observable behavior of the abstract machine to include additional library I/O functions [1.9/6] is extended to include threading library functions. When an exception is thrown and there is no matching exception handler in the same thread, behavior is undefined. The preferred behavior is the same as when there is no matching exception handler in a program [15.3/9]. That is, terminate() is called, and it is implementationdefined whether or not the stack is unwound.
11. Acknowledgements
William E. Kempf was the architect, designer, and implementor of Boost.Threads. Mac OS Carbon implementation written by Mac Murrett. Dave Moore provided initial submissions and further comments on the barrier , thread_pool , read_write_mutex , read_write_try_mutex and read_write_timed_mutex classes. Important contributions were also made by Jeremy Siek (lots of input on the design and on the implementation), Alexander Terekhov (lots of input on the Win32 implementation, especially in regards to boost::condition, as well as a lot of explanation of POSIX behavior), Greg Colvin (lots of input on the design), Paul Mclachlan, Thomas Matelich and Iain Hanson (for help in trying to get the build to work on other platforms), and Kevin S. Van Horn (for several updates/corrections to the documentation). Mike Glassford finished changes to Boost.Threads that were begun by William Kempf and moved them into the main CVS branch. He also addressed a number of issues that were brought up on the Boost developer's mailing list and provided some additions and changes to the read_write_mutex and related classes. The documentation was written by William E. Kempf. Beman Dawes provided additional documentation material and editing. Mike Glassford finished William Kempf's conversion of the documentation to BoostBook format and added a number of new sections. Discussions on the boost.org mailing list were essential in the development of Boost.Threads . As of August 1, 2001, participants included Alan Griffiths, Albrecht Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy Sawyer, Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade, Branko ibej, Brent Verner, Craig Henderson, Csaba Szepesvari, Dale Peakall, Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David Abrahams, David Allan Finch, Dejan Jelovic, Dietmar Kuehl, Douglas Gregor, Duncan Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot, Frank Gerlach, Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg Colvin, Gregory Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff Garland, Jeff Paquette, Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman, John (EBo) David, John Bandela, John Maddock, John Max Skaller, John Panzer, Jon Jagger , Karl Nelson, Kevlin Henney, KG Chandrasekhar, Levente Farkas, LieQuan Lee, Lois Goldthwaite, Luis Pedro Coelho, Marc Girod, Mark A. Borgerding, Mark Rodgers, Marshall Clow, Matthew Austern, Matthew Hurd, Michael D. Crawford, Michael H. Cox , Mike Haller, Miki Jovanovic, Nathan Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid, Philip Nash, Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom Reich, Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William Kempf. Apologies for anyone inadvertently missed.
310
Chapter 9. Boost.Threads
Bibliography
[AndrewsSchnieder83] ACM Computing Surveys. Vol. 15. No. 1. March, 1983. Gregory R. Andrews and Fred B. Schneider. Concepts and Notations for Concurrent Programming . Good general background reading. Includes descriptions of Path Expressions, Message Passing, and Remote Procedure Call in addition to the basics
[Boost] The Boost world wide web site. http://www.boost.org. Boost.Threads is one of many Boost libraries. The Boost web site includes a great deal of documentation and general information which applies to all Boost libraries. Current copies of the libraries including documentation and test programs may be downloaded from the web site.
[Hansen73] ACM Computing Surveys. Vol. 5. No. 4. December, 1983. Per Brinch. Concurrent Programming Concepts . "This paper describes the evolution of language features for multiprogramming from event queues and semaphores to critical regions and monitors." Includes analysis of why events are considered errorprone. Also noteworthy because of an introductory quotation from Christopher Alexander; Brinch Hansen was years ahead of others in recognizing pattern concepts applied to software, too.
[Butenhof97] Programming with POSIX Threads . David R. Butenhof. AddisonWesleyCopyright 1997. ISNB: 0201633922. This is a very readable explanation of threads and how to use them. Many of the insights given apply to all multithreaded programming, not just POSIX Threads
[Hoare74] Communications of the ACM. Vol. 17. No. 10. October, 1974. Monitors: An Operating System Structuring Concept . C.A.R. Hoare. 549557. Hoare and Brinch Hansen's work on Monitors is the basis for reliable multithreading patterns. This is one of the most often referenced papers in all of computer science, and with good reason.
[ISO98] Programming Language C++. ISO/IEC. 14882:1998(E). This is the official C++ Standards document. Available from the ANSI (American National Standards Institute) Electronic Standards Store.
[McDowellHelmbold89] Communications of the ACM. Vol. 21. No. 2. December, 1989. Charles E. McDowell. David P. Helmbold. Debugging Concurrent Programs. Identifies many of the unique failure modes and debugging difficulties associated with concurrent programs.
[SchmidtPyarali] Strategies for Implementing POSIX Condition Variables on Win32. Douglas C. Schmidt and Irfan Pyarali. Department of Computer Science, Washington University, St. Louis, Missouri. Rationale for understanding Boost.Threads condition variables. Note that Alexander Terekhov found some bugs in the implementation given in this article, so pthreadswin32 and Boost.Threads are even more complicated yet.
311
Chapter 9. Boost.Threads
[SchmidtStalRohnertBuschmann] PatternOriented Architecture Volume 2. Patterns for Concurrent and Networked Objects. POSA2. Douglas C. Schmidt, Michael, Hans Rohnert, and Frank Buschmann. WileyCopyright 2000. This is a very good explanation of how to apply several patterns useful for concurrent programming. Among the patterns documented is the Monitor Pattern mentioned frequently in the Boost.Threads documentation.
[Stroustrup] The C++ Programming Language. Special Edition. AddisonWesleyCopyright 2000. ISBN: 0201700735. The first book a C++ programmer should own. Note that the 3rd edition (and subsequent editions like the Special Edition) has been rewritten to cover the ISO standard language and library.
312
Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1. Introduction
The 3state boolean library contains a single class, boost::logic::tribool, along with support functions and operator overloads that implement 3state boolean logic.
2. Tutorial
2.1. Basic usage
The tribool class acts like the builtin bool type, but for 3state boolean logic. The three states are true, false, and indeterminate, where the first two states are equivalent to those of the C++ bool type and the last state represents an unknown boolean value (that may be true or false, we don't know). The tribool class supports conversion from bool values and literals along with its own indeterminate keyword:
tribool b(true); b = false; b = indeterminate; tribool b2(b);
tribool supports conversions to bool for use in conditional statements. The conversion to bool will be true when the value of the tribool is always true, and false otherwise. Consequently, the following idiom may be used to determine which of the three states a tribool currently holds:
tribool b = some_operation(); if (b) { // b is true } else if (!b) { // b is false } else { // b is indeterminate }
tribool supports the 3state logic operators ! (negation), && (AND), and || (OR), with bool and tribool values. For instance:
tribool x = some_op(); tribool y = some_other_op(); if (x && y) { // both x and y are true } else if (!(x && y)) { // either x or y is false } else { // neither x nor y is false, but we don't know that both are true
313
Similarly, tribool supports 3state equality comparisons via the operators == and !=. These operators differ from "normal" equality operators in C++ because they return a tribool, because potentially we might not know the result of a comparison (try to compare true and indeterminate). For instance:
tribool x(true); tribool y(indeterminate); assert(x == x); // okay, x == x returns true assert(x == true); // okay, can compare tribools and bools
The indeterminate keyword (representing the indeterminate tribool value) doubles as a function to check if the value of a tribool is indeterminate, e.g.,
tribool x = try_to_do_something_tricky(); if (indeterminate(x)) { // value of x is indeterminate } else { // report success or failure of x }
tribool input and output is sensitive to the stream's current locale. The strings associated with false and true values are contained in the standard std::numpunct facet, and the string naming the indeterminate type is contained in the indeterminate_name facet. To replace the name of the indeterminate state, you need to imbue your stream with a local containing a indeterminate_name facet, e.g.:
BOOST_TRIBOOL_THIRD_STATE(maybe) locale global; locale test_locale(global, new indeterminate_name<char>("maybe")); cout.imbue(test_locale); tribool x(maybe); cout << boolalpha << x << endl; // Prints "maybe"
314
If you C++ standard library implementation does not support locales, tribool input/output will still work, but you will be unable to customize the strings printed/parsed when boolalpha is set.
3. Reference
3.1. Header <boost/logic/tribool.hpp>
BOOST_TRIBOOL_THIRD_STATE(Name) namespace boost { namespace logic { class tribool; bool indeterminate(tribool, unspecified = unspecified); tribool operator!(tribool); tribool operator&&(tribool, tribool); tribool operator&&(tribool, bool); tribool operator&&(bool, tribool); tribool operator&&(indeterminate_keyword_t, tribool); tribool operator&&(tribool, indeterminate_keyword_t); tribool operator||(tribool, tribool); tribool operator||(tribool, bool); tribool operator||(bool, tribool); tribool operator||(indeterminate_keyword_t, tribool); tribool operator||(tribool, indeterminate_keyword_t); tribool operator==(tribool, tribool); tribool operator==(tribool, bool); tribool operator==(bool, tribool); tribool operator==(indeterminate_keyword_t, tribool); tribool operator==(tribool, indeterminate_keyword_t); tribool operator!=(tribool, tribool); tribool operator!=(tribool, bool); tribool operator!=(bool, tribool); tribool operator!=(indeterminate_keyword_t, tribool); tribool operator!=(tribool, indeterminate_keyword_t); } }
Description
315
1. tribool(); Construct a new 3state boolean value with the value 'false'. Throws Will not throw. 2. tribool(bool value); Construct a new 3state boolean value with the given boolean value, which may be true or false . Throws Will not throw. 3. tribool(indeterminate_keyword_t ); Construct a new 3state boolean value with an indeterminate value. Throws Will not throw.
1. operator safe_bool() const; Use a 3state boolean in a boolean context. Will evaluate true in a boolean context only when the 3state boolean is definitely true. Returns true if the 3state boolean is true, false otherwise Throws Will not throw.
Description
The indeterminate function has a dual role. It's first role is as a unary function that tells whether the tribool value is in the "indeterminate" state. It's second role is as a keyword representing the indeterminate (just like "true" and "false" represent the true and false states). If you do not like the name "indeterminate", and would prefer to use a different name, see the macro BOOST_TRIBOOL_THIRD_STATE . Returns x.value == tribool::indeterminate_value Throws Will not throw.
316
Description
Returns the logical negation of the tribool, according to the table: ! false true indeterminate Throws Will not throw. true false indeterminate
Description
Returns the result of logically ANDing the two tribool values, according to the following table: && false true indeterminate Throws Will not throw. false false false false true false true indeterminate indeterminate false indeterminate indeterminate
317
Description
Returns the result of logically ORing the two tribool values, according to the following table: || false true indeterminate Throws Will not throw. false false true indeterminate true true true true indeterminate indeterminate true indeterminate
Description
Returns the result of comparing two tribool values, according to the following table: == false true indeterminate Throws Will not throw. false true false indeterminate true false true indeterminate indeterminate indeterminate indeterminate indeterminate
318
Description
Returns the result of comparing two tribool values for inequality, according to the following table: != false true indeterminate Throws Will not throw. false false true indeterminate true true false indeterminate indeterminate indeterminate indeterminate indeterminate
Description
Use this macro to declare a new name for the third state of a tribool. This state can have any number of new names (in addition to indeterminate ), all of which will be equivalent. The new name will be placed in the namespace in which the macro is expanded. Example: BOOST_TRIBOOL_THIRD_STATE(true_or_false) tribool x(true_or_false); // potentially set x if (true_or_false(x)) { // don't know what x is }
319
Description
The facet is used to perform I/O on tribool values when std::boolalpha has been specified. This class template is only available if the C++ standard library implementation supports locales.
indeterminate_name construct/copy/destruct
1. string_type name() const; Function template get_default_indeterminate_name boost::logic::get_default_indeterminate_name tribool with the given character type T. Returns a string containing the default name for the indeterminate value of a
320
Description
This routine is used by the input and output streaming operators for tribool when there is no locale support or the stream's locale does not contain the indeterminate_name facet.
Description
When the value of x is either true or false , this routine is semantically equivalent to:
out << static_cast<bool>(x);
When x has an indeterminate value, it outputs either the integer value 2 (if (out.flags() & std::ios_base::boolalpha) == 0 ) or the name of the indeterminate value. The name of the indeterminate value comes from the indeterminate_name facet (if it is defined in the output stream's locale), or from the get_default_indeterminate_name function (if it is not defined in the locale or if the C++ standard library implementation does not support locales). Returns out
Description
When (out.flags() & std::ios_base::boolalpha) == 0 , this function reads a long value from the input stream in and converts that value to a tribool. If that value is 0, x becomes false ; if it is 1, x becomes true ; if it is 2, becomesindetermine ; otherwise, the operation fails (and the fail bit is set on the input stream in ). When (out.flags() & std::ios_base::boolalpha) != 0 , this function first determines the names of the false, true, and indeterminate values. The false and true names are extracted from the std::numpunct facet of the input stream's locale (if the C++ standard library implementation supports locales), or from the default_false_name and default_true_name functions (if there is no locale support). The indeterminate name is extracted from the appropriate
321
indeterminate_name facet (if it is available in the input stream's locale), or from the get_default_indeterminate_name function (if the C++ standard library implementation does not support locales, or the indeterminate_name facet is not specified for this locale object). The input is then matched to each of these names, and the tribool x is assigned the value corresponding to the longest name that matched. If no name is matched or all names are empty, the operation fails (and the fail bit is set on the input stream in ). Returns in
4. Testsuite
4.1. Acceptance tests
Test tribool_test.cpp tribool_rename_test.cpp tribool_io_test.cpp Type run run run Description Test all features of the boost::logic::tribool class. Test the use of the BOOST_TRIBOOL_THIRD_STATE macro. Test tribool input/output. If failing...
322
Permission to copy, use, sell and distribute this software is granted provided this copyright notice appears in all copies. Permission to modify the code and to distribute modified code is granted provided this copyright notice appears in all copies, and a notice that the code was modified is included with the copyright notice. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
1. Introduction
1.1. Abstract
The variant class template is a safe, generic, stackbased discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner. Whereas standard containers such as std::vector may be thought of as "multivalue, single type," variant is "multitype, single value." Notable features of boost::variant include: Full value semantics, including adherence to standard overload resolution rules for conversion operations. Compiletime typesafe value visitation via boost::apply_visitor. Runtime checked explicit value retrieval via boost::get. Support for recursive variant types via both boost::make_recursive_variant and boost::recursive_wrapper. Efficient implementation stackbased when possible (see Section 4.1, "NeverEmpty" Guarantee for more details).
1.2. Motivation
1.2.1. Problem Many times, during the development of a C++ program, the programmer finds himself in need of manipulating several distinct types in a uniform manner. Indeed, C++ features direct language support for such types through its union keyword:
union { int i; double d; } u; u.d = 3.14; u.i = 3; // overwrites u.d (OK: u.d is a POD type)
C++'s union construct, however, is nearly useless in an objectoriented environment. The construct entered the language primarily as a means for preserving compatibility with C, which supports only POD (Plain Old Data) types, and so does not accept types exhibiting nontrivial construction or destruction:
union { int i; std::string s; // illegal: std::string is not a POD type! } u;
Clearly another approach is required. Typical solutions feature the dynamicallocation of objects, which are subsequently manipulated through a common base type (often a virtual base class [Hen01] or, more dangerously, a void*). Objects of concrete type may be then retrieved by way of a polymorphic downcast construct (e.g., dynamic_cast,
323
boost::any_cast, etc.). However, solutions of this sort are highly errorprone, due to the following: Downcast errors cannot be detected at compiletime. Thus, incorrect usage of downcast constructs will lead to bugs detectable only at runtime. Addition of new concrete types may be ignored. If a new concrete type is added to the hierarchy, existing downcast code will continue to work asis, wholly ignoring the new type. Consequently, the programmer must manually locate and modify code at numerous locations, which often results in runtime errors that are difficult to find. Furthermore, even when properly implemented, these solutions tend to incur a relatively significant abstraction penalty due to the use of the heap, virtual function calls, and polymorphic downcasts. 1.2.2. Solution: A Motivating Example The boost::variant class template addresses these issues in a safe, straightforward, and efficient manner. The following example demonstrates how the class can be used:
#include "boost/variant.hpp" #include <iostream> class my_visitor : public boost::static_visitor<int> { public: int operator()(int i) const { return i; } int operator()(const std::string & str) const { return str.length(); } }; int main() { boost::variant< int, std::string > u("hello world"); std::cout << u; // output: hello world int result = boost::apply_visitor( my_visitor(), u ); std::cout << result; // output: 11 (i.e., length of "hello world") }
2. Tutorial
2.1. Basic Usage
A discriminated union container on some set of types is defined by instantiating the boost::variant class template with the desired types. These types are called bounded types and are subject to the requirements of the BoundedType concept. Any number of bounded types may be specified, up to some implementationdefined limit (see BOOST_VARIANT_LIMIT_TYPES). For example, the following declares a discriminated union container on int and std::string:
boost::variant< int, std::string > v;
By default, a variant defaultconstructs its first bounded type, so v initially contains int(0). If this is not desired, or if the first bounded type is not defaultconstructible, a variant can be constructed directly from any value convertible to one of its bounded types. Similarly, a variant can be assigned any value convertible to one of its bounded types, as
324
Now v contains a std::string equal to "hello". We can demonstrate this by streaming v to standard output:
std::cout << v << std::endl;
Usually though, we would like to do more with the content of a variant than streaming. Thus, we need some way to access the contained value. There are two ways to accomplish this: apply_visitor, which is safest and very powerful, and get<T>, which is sometimes more convenient to use. For instance, suppose we wanted to concatenate to the string contained in v. With value retrieval by get, this may be accomplished quite simply, as seen in the following:
std::string& str = boost::get<std::string>(v); str += " world! ";
As desired, the std::string contained by v now is equal to "hello world! ". Again, we can demonstrate this by streaming v to standard output:
std::cout << v << std::endl;
While use of get is perfectly acceptable in this trivial example, get generally suffers from several significant shortcomings. For instance, if we were to write a function accepting a variant<int, std::string>, we would not know whether the passed variant contained an int or a std::string. If we insisted upon continued use of get, we would need to query the variant for its contained type. The following function, which "doubles" the content of the given variant, demonstrates this approach:
void times_two( boost::variant< int, std::string > & operand ) { if ( int* pi = boost::get<int>( &v ) ) *pi *= 2; else if ( std::string* pstr = boost::get<std::string>( &v ) ) *pstr += *pstr; }
However, such code is quite brittle, and without careful attention will likely lead to the introduction of subtle logical errors detectable only at runtime. For instance, consider if we wished to extend times_two to operate on a variant with additional bounded types. Specifically, let's add std::complex<double> to the set. Clearly, we would need to at least change the function declaration:
void times_two( boost::variant< int, std::string, std::complex<double> > & operand ) { // as above...? }
Of course, additional changes are required, for currently if the passed variant in fact contained a std::complex value, times_two would silently return without any of the desired sideeffects and without any error. In this case, the fix is obvious. But in more complicated programs, it could take considerable time to identify and locate the error in the first place. Thus, realworld use of variant typically demands an access mechanism more robust than get. For this reason, variant supports compiletime checked visitation via apply_visitor. Visitation requires that the programmer explicitly handle (or ignore) each bounded type. Failure to do so results in a compiletime error. Visitation of a variant requires a visitor object. The following demonstrates one such implementation of a visitor implementating behavior identical to times_two:
class times_two_visitor : public boost::static_visitor<>
325
With the implementation of the above visitor, we can then apply it to v, as seen in the following:
boost::apply_visitor( times_two_visitor(), v );
As expected, the content of v is now a std::string equal to "hello world! hello world! ". (We'll skip the verification this time.) In addition to enhanced robustness, visitation provides another important advantage over get: the ability to write generic visitors. For instance, the following visitor will "double" the content of any variant (provided its bounded types each support operator+=):
class times_two_generic : public boost::static_visitor<> { public: template <typename T> void operator()( T & operand ) const { operand += operand; } };
While the initial setup costs of visitation may exceed that required for get, the benefits quickly become significant. Before concluding this section, we should explore one last benefit of visitation with apply_visitor: delayed visitation. Namely, a special form of apply_visitor is available that does not immediately apply the given visitor to any variant but rather returns a function object that operates on any variant given to it. This behavior is particularly useful when operating on sequences of variant type, as the following demonstrates:
std::vector< boost::variant<int, std::string> > vec; vec.push_back( 21 ); vec.push_back( "hello " ); times_two_generic visitor; std::for_each( vec.begin(), vec.end() , boost::apply_visitor(visitor) );
section, each feature presented below is largely independent of the others. Accordingly, this section is not necessarily intended to be read linearly or in its entirety. 2.2.1. Preprocessor macros While the variant class template's variadic parameter list greatly simplifies use for specific instantiations of the template, it significantly complicates use for generic instantiations. For instance, while it is immediately clear how one might write a function accepting a specific variant instantiation, say variant<int, std::string>, it is less clear how one might write a function accepting any given variant. Due to the lack of support for true variadic template parameter lists in the C++98 standard, the preprocessor is needed. While the Preprocessor library provides a general and powerful solution, the need to repeat BOOST_VARIANT_LIMIT_TYPES unnecessarily clutters otherwise simple code. Therefore, for common usecases, this library provides its own macro BOOST_VARIANT_ENUM_PARAMS. This macro simplifies for the user the process of declaring variant types in function templates or explicit partial specializations of class templates, as shown in the following:
// general cases template <typename T> void some_func(const T &); template <typename T> class some_class; // function template overload template <BOOST_VARIANT_ENUM_PARAMS(typename T)> void some_func(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &); // explicit partial specialization template <BOOST_VARIANT_ENUM_PARAMS(typename T)> class some_class< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >;
2.2.2. Using a type sequence to specify bounded types While convenient for typical uses, the variant class template's variadic template parameter list is limiting in two significant dimensions. First, due to the lack of support for true variadic template parameter lists in C++, the number of parameters must be limited to some implementationdefined maximum (namely, BOOST_VARIANT_LIMIT_TYPES). Second, the nature of parameter lists in general makes compiletime manipulation of the lists excessively difficult. To solve these problems, make_variant_over< Sequence > exposes a variant whose bounded types are the elements of Sequence (where Sequence is any type fulfilling the requirements of MPL's Sequence concept). For instance,
typedef mpl::vector< std::string > types_initial; typedef mpl::push_front< types_initial, int >::type types; boost::make_variant_over< types >::type v1;
behaves equivalently to
boost::variant< int, std::string > v2;
Portability: Unfortunately, due to standard conformance issues in several compilers, make_variant_over is not universally available. On these compilers the library indicates its lack of support for the syntax via the definition of the preprocessor symbol BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT. 2.2.3. Recursive variant types Recursive types facilitate the construction of complex semantics from simple syntax. For instance, nearly every programmer is familiar with the canonical definition of a linked list implementation, whose simple definition allows sequences of unlimited length:
327
The nature of variant as a generic class template unfortunately precludes the straightforward construction of recursive variant types. Consider the following attempt to construct a structure for simple mathematical expressions:
struct add; struct sub; template <typename OpTag> struct binary_op; typedef boost::variant< int , binary_op<add> , binary_op<sub> > expression; template <typename OpTag> struct binary_op { expression left; // variant instantiated here... expression right; binary_op( const expression & lhs, const expression & rhs ) : left(lhs), right(rhs) { } }; // ...but binary_op not complete until here!
While wellintentioned, the above approach will not compile because binary_op is still incomplete when the variant type expression is instantiated. Further, the approach suffers from a more significant logical flaw: even if C++ syntax were different such that the above example could be made to "work," expression would need to be of infinite size, which is clearly impossible. To overcome these difficulties, variant includes special support for the boost::recursive_wrapper class template, which breaks the circular dependency at the heart of these problems. Further, boost::make_recursive_variant provides a more convenient syntax for declaring recursive variant types. Tutorials for use of these facilities is described in Section 2.2.3.1, Recursive types with recursive_wrapper and Section 2.2.3.2, Recursive types with make_recursive_variant .
2.2.3.1. Recursive types with recursive_wrapper
The following example demonstrates how recursive_wrapper could be used to solve the problem presented in Section 2.2.3, Recursive variant types :
typedef boost::variant< int , boost::recursive_wrapper< binary_op<add> > , boost::recursive_wrapper< binary_op<sub> > > expression;
Because variant provides special support for recursive_wrapper, clients may treat the resultant variant as though the wrapper were not present. This is seen in the implementation of the following visitor, which calculates the value of an expression without any reference to recursive_wrapper:
class calculator : public boost::static_visitor<int> { public:
328
For some applications of recursive variant types, a user may be able to sacrifice the full flexibility of using recursive_wrapper with variant for the following convenient syntax:
typedef boost::make_recursive_variant< int , std::vector< boost::recursive_variant_ > >::type int_tree_t;
To be clear, one might represent the resultant content of var as ( 1 ( 3 5 ) 7 ). Finally, note that a type sequence can be used to specify the bounded types of a recursive variant via the use of boost::make_recursive_variant_over, whose semantics are the same as make_variant_over (which is described in Section 2.2.2, Using a type sequence to specify bounded types ).
329
Portability: Unfortunately, due to standard conformance issues in several compilers, make_recursive_variant is not universally supported. On these compilers the library indicates its lack of support via the definition of the preprocessor symbol BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT. Thus, unless working with highlyconformant compilers, maximum portability will be achieved by instead using recursive_wrapper, as described in Section 2.2.3.1, Recursive types with recursive_wrapper . 2.2.4. Binary visitation As the tutorial above demonstrates, visitation is a powerful mechanism for manipulating variant content. Binary visitation further extends the power and flexibility of visitation by allowing simultaneous visitation of the content of two different variant objects. Notably this feature requires that binary visitors are incompatible with the visitor objects discussed in the tutorial above, as they must operate on two arguments. The following demonstrates the implementation of a binary visitor:
class are_strict_equals : public boost::static_visitor<bool> { public: template <typename T, typename U> bool operator()( const T &, const U & ) { return false; // cannot compare different types } template <typename T> bool operator()( const T & lhs, const T & rhs ) { return lhs == rhs; } };
Finally, we must note that the function object returned from the "delayed" form of apply_visitor also supports binary visitation, as the following demonstrates:
typedef boost::variant<double, std::string> my_variant; std::vector< my_variant > seq1; seq1.push_back("pi is close to "); seq1.push_back(3.14); std::list< my_variant > seq2; seq2.push_back("pi is close to "); seq2.push_back(3.14); are_strict_equals visitor; assert( std::equal( v1.begin(), v1.end(), v2.begin() , boost::apply_visitor( visitor ) ) );
330
3. Reference
3.1. Concepts
3.1.1. BoundedType The requirements on a bounded type are as follows: CopyConstructible [20.1.3]. Destructor upholds the nothrow exceptionsafety guarantee. Complete at the point of variant template instantiation. (See boost::recursive_wrapper<T> for a type wrapper that accepts incomplete types to enable recursive variant types.) Every type specified as a template argument to variant must at minimum fulfill the above requirements. In addition, certain features of variant are available only if its bounded types meet the requirements of these following additional concepts: Assignable: variant is itself Assignable if and only if every one of its bounded types meets the requirements of the concept. (Note that toplevel constqualified types and reference types do not meet these requirements.) DefaultConstructible [20.1.4]: variant is itself DefaultConstructible if and only if its first bounded type (i.e., T1) meets the requirements of the concept. EqualityComparable: variant is itself EqualityComparable if and only if every one of its bounded types meets the requirements of the concept. LessThanComparable: variant is itself LessThanComparable if and only if every one of its bounded types meets the requirements of the concept. OutputStreamable: variant is itself OutputStreamable if and only if every one of its bounded types meets the requirements of the concept. 3.1.2. StaticVisitor The requirements on a static visitor of a type T are as follows: Must allow invocation as a function by overloading operator(), unambiguously accepting any value of type T. Must expose inner type result_type. (See boost::visitor_ptr for a solution to using functions as visitors.) If result_type is not void, then each operation of the function object must return a value implicitly convertible to result_type.
3.1.2.1. Examples
The following class satisfies the requirements of a static visitor of several types (i.e., explicitly: int and std::string; or, e.g., implicitly: short and const char *; etc.):
class my_visitor : public boost::static_visitor<int> { public: int operator()(int i) { return i * 2; } int operator()(const std::string& s) { return s.length(); } };
331
Another example is the following class, whose functioncall operator is a member template, allowing it to operate on values of many types. Thus, the following class is a visitor of any type that supports streaming output (e.g., int, double, std::string, etc.):
class printer : public boost::static_visitor<> { template <typename T> void operator()(const T& t) { std::cout << t << std::endl; } };
3.1.3. OutputStreamable The requirements on an output streamable type T are as follows: For any object t of type T, std::cout << t must be a valid expression.
Macro BOOST_VARIANT_LIMIT_TYPES BOOST_VARIANT_LIMIT_TYPES Expands to the length of the template parameter list for variant.
Synopsis BOOST_VARIANT_LIMIT_TYPES
Description
Note: Conforming implementations of variant must allow at least ten template arguments. That is, BOOST_VARIANT_LIMIT_TYPES must be greater or equal to 10.
332
Description
Expands to a commaseparated sequence of length BOOST_VARIANT_LIMIT_TYPES, where each element in the sequence consists of the concatenation of param with its zerobased index into the sequence. That is, param ## 0, param ## 1, ..., param ## BOOST_VARIANT_LIMIT_TYPES 1. Rationale: This macro greatly simplifies for the user the process of declaring variant types in function templates or explicit partial specializations of class templates, as shown in the tutorial.
Macro BOOST_VARIANT_ENUM_SHIFTED_PARAMS BOOST_VARIANT_ENUM_SHIFTED_PARAMS Enumerate all but the first parameter for use with variant.
Synopsis BOOST_VARIANT_ENUM_SHIFTED_PARAMS(param)
Description
Expands to a commaseparated sequence of length BOOST_VARIANT_LIMIT_TYPES 1, where each element in the sequence consists of the concatenation of param with its onebased index into the sequence. That is, param ## 1, ..., param ## BOOST_VARIANT_LIMIT_TYPES 1. Note: This macro results in the same expansion as BOOST_VARIANT_ENUM_PARAMS but without the first term.
Macro BOOST_VARIANT_NO_REFERENCE_SUPPORT BOOST_VARIANT_NO_REFERENCE_SUPPORT Indicates variant does not support references as bounded types.
Synopsis BOOST_VARIANT_NO_REFERENCE_SUPPORT
Description
333
Macro BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT Indicates absence of support for specifying the bounded types of a variant by the elements of a type sequence.
Synopsis BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT
Description
Defined only if make_variant_over and make_recursive_variant_over are not supported for some reason on the target compiler.
Description
Defined only if make_recursive_variant does not operate as documented on the target compiler, but rather in an implementationdefined manner. Implementation Note: If BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT is defined for the target compiler, the current implementation uses the MPL lambda mechanism to approximate the desired behavior. (In most cases, however, such compilers do not have full lambda support either.)
Class template variant boost::variant Safe, generic, stackbased discriminated union container.
334
Description
The variant class template (inspired by Andrei Alexandrescu's class of the same name [Ale01A]) is an efficient, recursivecapable, bounded discriminated union value type capable of containing any value type (either POD or nonPOD). It supports construction from any type convertible to one of its bounded types or from a source variant whose bounded types are each convertible to one of the destination variant's bounded types. As well, through apply_visitor, variant supports compiletime checked, typesafe visitation; and through get, variant supports runtime checked, typesafe value retrieval. Notes: The bounded types of the variant are exposed via the nested typedef types, which is an MPLcompatible Sequence containing the set of types that must be handled by any visitor to the variant. All members of variant satisfy at least the basic guarantee of exceptionsafety. That is, all operations on a variant remain defined even after previous operations have failed. Each type specified as a template argument to variant must meet the requirements of the BoundedType concept. Each type specified as a template argument to variant must be distinct after removal of qualifiers. Thus, for instance, both variant<int, int> and variant<int, const int> have undefined behavior. Conforming implementations of variant must allow at least ten types as template arguments. The exact number of allowed arguments is exposed by the preprocessor macro BOOST_VARIANT_LIMIT_TYPES. (See make_variant_over for a means to specify the bounded types of a variant by the elements of an MPL or compatible Sequence, thus overcoming this limitation.)
335
1. variant(); Requires The first bounded type of the variant (i.e., T1) must fulfill the requirements of the DefaultConstructible [20.1.4] concept. Postconditions Content of *this is the default value of the first bounded type (i.e, T1). Throws May fail with any exceptions arising from the default constructor of T1. 2. variant(const variant & other); Postconditions Content of *this is a copy of the content of other. Throws May fail with any exceptions arising from the copy constructor of other's contained type. 3. template<typename T> variant(T & operand); Requires T must be unambiguously convertible to one of the bounded types (i.e., T1, T2, etc.). Postconditions Content of *this is the best conversion of operand to one of the bounded types, as determined by standard overload resolution rules. Throws May fail with any exceptions arising from the conversion of operand to one of the bounded types. 4. template<typename T> variant(const T & operand); Notes Same semantics as previous constructor, but allows construction from temporaries. 5. template<typename U1, typename U2, ..., typename UN>
variant(variant<U1, U2, ..., UN> & operand);
Requires Every one of U1, U2, ..., UN must have an unambiguous conversion to one of the bounded types (i.e., T1, T2, ..., TN). Postconditions If variant<U1, U2, ..., UN> is itself one of the bounded types, then content of *this is a copy of operand. Otherwise, content of *this is the best conversion of the content of operand to one of the bounded types, as determined by standard overload resolution rules. Throws If variant<U1, U2, ..., UN> is itself one of the bounded types, then may fail with any exceptions arising from the copy constructor of variant<U1, U2, ..., UN>. Otherwise, may fail with any exceptions arising from the conversion of the content of operand to one of the bounded types. 6. template<typename U1, typename U2, ..., typename UN>
variant(const variant<U1, U2, ..., UN> & operand);
Notes Same semantics as previous constructor, but allows construction from temporaries. 7. ~variant(); Effects Destroys the content of *this. Throws Will not throw.
336
1. void swap(variant & other); Requires Every bounded type must fulfill the requirements of the Assignable concept. Effects Interchanges the content of *this and other. Throws If the contained type of other is the same as the contained type of *this, then may fail with any exceptions arising from the swap of the contents of *this and other. Otherwise, may fail with any exceptions arising from either of the copy constructors of the contained types. Also, in the event of insufficient memory, may fail with std::bad_alloc (why?). 2. variant & operator=(const variant & rhs); Requires Every bounded type must fulfill the requirements of the Assignable concept. Effects If the contained type of rhs is the same as the contained type of *this, then assigns the content of rhs into the content of *this. Otherwise, makes the content of *this a copy of the content of rhs, destroying the previous content of *this. Throws If the contained type of rhs is the same as the contained type of *this, then may fail with any exceptions arising from the assignment of the content of rhs into the content *this. Otherwise, may fail with any exceptions arising from the copy constructor of the contained type of rhs. Also, in the event of insufficient memory, may fail with std::bad_alloc (why?). 3. template<typename T> variant & operator=(const T & rhs); Requires T must be unambiguously convertible to one of the bounded types (i.e., T1, T2, etc.). Every bounded type must fulfill the requirements of the Assignable concept. Effects If the contained type of *this is T, then assigns rhs into the content of *this. Otherwise, makes the content of *this the best conversion of rhs to one of the bounded types, as determined by standard overload resolution rules, destroying the previous content of *this. Throws If the contained type of *this is T, then may fail with any exceptions arising from the assignment of rhs into the content *this. Otherwise, may fail with any exceptions arising from the conversion of rhs to one of the bounded types. Also, in the event of insufficient memory, may fail with std::bad_alloc (why?).
variant queries
1. int which() const; Returns The zerobased index into the set of bounded types of the contained type of *this. (For instance, if called on a variant<int, std::string> object containing a std::string, which() would return 1.) Throws Will not throw. 2. bool empty() const; Returns false: variant always contains exactly one of its bounded types. (See Section 4.1, "NeverEmpty" Guarantee for more information.) Rationale
337
Facilitates generic compatibility with boost::any. Throws Will not throw. 3. const std::type_info & type() const; Returns typeid(x), where x is the the content of *this. Throws Will not throw.
variant relational
1.
bool operator==(const variant & rhs) const; template<typename U> void operator==(const U & ) const;
Notes The overload returning void exists only to prohibit implicit conversion of the operator's righthand side to variant; thus, its use will (purposefully) result in a compiletime error. Requires Every bounded type of the variant must fulfill the requirements of the EqualityComparable concept. Returns true iff which() == rhs.which()andcontent_this == content_rhs, where content_this is the content of *this and content_rhs is the content of rhs. Throws If which() == rhs.which() then may fail with any exceptions arising from operator==(T,T), where T is the contained type of *this. 2.
bool operator<(const variant & rhs) const; template<typename U> void operator<(const U & ) const;
Notes The overload returning void exists only to prohibit implicit conversion of the operator's righthand side to variant; thus, its use will (purposefully) result in a compiletime error. Requires Every bounded type of the variant must fulfill the requirements of the LessThanComparable concept. Returns If which() == rhs.which() then: content_this < content_rhs, where content_this is the content of *this and content_rhs is the content of rhs. Otherwise: which() < rhs.which(). Throws If which() == rhs.which() then may fail with any exceptions arising from operator<(T,T), where T is the contained type of *this.
338
Effects Swaps lhs with rhs by application of variant::swap. Throws May fail with any exception arising from variant::swap.
Description
Requires Every bounded type of the variant must fulfill the requirements of the OutputStreamable concept. Effects Calls out << x, where x is the content of rhs.
Class template make_variant_over boost::make_variant_over Exposes a variant whose bounded types are the elements of the given type sequence.
Synopsis template<typename Sequence> class make_variant_over { public: // types typedef variant< unspecified > type; };
Description
type has behavior equivalent in every respect to variant< Sequence[0], Sequence[1], ... > (where Sequence[i] denotes the ith element of Sequence), except that no upper limit is imposed on the number of types. Notes: Sequence must meet the requirements of MPL's Sequence concept. Due to standard conformance problems in several compilers, make_variant_over may not be supported on your compiler. See BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT for more information.
339
Description
type has behavior equivalent in every respect to some variant< U1, U2, ..., UN >, where each type Ui is the result of the corresponding type Ti undergone a transformation function. The following pseudocode specifies the behavior of this transformation (call it substitute): If Ti is boost::recursive_variant_ then: variant< U1, U2, ..., UN >; Else if Ti is of the form X * then: substitute(X) *; Else if Ti is of the form X & then: substitute(X) &; Else if Ti is of the form R (*)( X1, X2, ..., XN ) then: substitute(R) (*)( substitute(X1), substitute(X2), ..., substitute(XN) ); Else if Ti is of the form F < X1, X2, ..., XN > then: F< substitute(X1), substitute(X2), ..., substitute(XN) >; Else: Ti. Note that cvqualifiers are preserved and that the actual process is generally a bit more complicated. However, the above does convey the essential idea as well as describe the extent of the substititions. Use of make_recursive_variant is demonstrated in Section 2.2.3.2, Recursive types with make_recursive_variant . Portability: Due to standard conformance issues in several compilers, make_recursive_variant is not universally supported. On these compilers the library indicates its lack of support via the definition of the preprocessor symbol BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT.
Class template make_recursive_variant_over boost::make_recursive_variant_over Exposes a recursive variant whose bounded types are the elements of the given type sequence.
340
Description
type has behavior equivalent in every respect to make_recursive_variant< Sequence[0], Sequence[1], ... >::type (where Sequence[i] denotes the ith element of Sequence), except that no upper limit is imposed on the number of types. Notes: Sequence must meet the requirements of MPL's Sequence concept. Due to standard conformance problems in several compilers, make_recursive_variant_over may not be supported on your compiler. See BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT for more information.
341
The recursive_wrapper class template has an interface similar to a simple value container, but its content is allocated dynamically. This allows recursive_wrapper to hold types T whose member data leads to a circular dependency (e.g., a data member of T has a data member of type T). The application of recursive_wrapper is easiest understood in context. See Section 2.2.3.1, Recursive types with recursive_wrapper for a demonstration of a common use of the class template. Notes: Any type specified as the template argument to recursive_wrapper must be capable of construction via operator new. Thus, for instance, references are not supported.
recursive_wrapper construct/copy/destruct
1. recursive_wrapper(); Initializes *this by default construction of T. Requires T must fulfill the requirements of the DefaultConstructible [20.1.4] concept. Throws May fail with any exceptions arising from the default constructor of T or, in the event of insufficient memory, with std::bad_alloc. 2. recursive_wrapper(const recursive_wrapper & other); Copies the content of other into *this. Throws May fail with any exceptions arising from the copy constructor of T or, in the event of insufficient memory, with std::bad_alloc. 3. recursive_wrapper(const T & operand); Copies operand into *this. Throws May fail with any exceptions arising from the copy constructor of T or, in the event of insufficient memory, with std::bad_alloc. 4. ~recursive_wrapper(); Deletes the content of *this. Throws Will not throw.
recursive_wrapper modifiers
1. void swap(recursive_wrapper & other); Exchanges contents of *this and other. Throws Will not throw. 2. recursive_wrapper & operator=(const recursive_wrapper & rhs);
342
Assigns the content of rhs to the content of *this. Requires T must fulfill the requirements of the Assignable concept. Throws May fail with any exceptions arising from the assignment operator of T. 3. recursive_wrapper & operator=(const T & rhs); Assigns rhs into the content of *this. Requires T must fulfill the requirements of the Assignable concept. Throws May fail with any exceptions arising from the assignment operator of T.
recursive_wrapper queries
1.
T & get(); const T & get() const;
Class template is_recursive_wrapper boost::is_recursive_wrapper Determines whether the specified type is a specialization of recursive_wrapper.
Synopsis template<typename T> class is_recursive_wrapper { public: // types typedef unspecified type; // static constants static const bool value = unspecified; };
Description
343
Class template unwrap_recursive_wrapper boost::unwrap_recursive_wrapper Unwraps the specified argument if given a specialization of recursive_wrapper.
Synopsis template<typename T> class unwrap_recursive_wrapper { public: // types typedef unspecified type; };
Description
344
Adapts the function given at construction for use as a function object. This is useful, for example, when one needs to operate on each element of a sequence of variant objects using a standard library algorithm such as std::for_each. See the "visitoronly" form of apply_visitor for a simple way to create apply_visitor_delayed_t objects.
apply_visitor_delayed_t construct/copy/destruct
1. explicit apply_visitor_delayed_t(Visitor & visitor); Effects Constructs the function object with the given visitor.
1.
template<typename Variant> result_type operator()(Variant & operand); template<typename Variant1, typename Variant2> result_type operator()(Variant1 & operand1, Variant2 & operand2);
Function apply_visitor boost::apply_visitor Allows compiletime checked typesafe application of the given visitor to the content of the given variant, ensuring that all types are handled by the visitor.
Synopsis template<typename Visitor, typename Variant> typename Visitor::result_type apply_visitor(Visitor & visitor, Variant & operand); template<typename Visitor, typename Variant> typename Visitor::result_type apply_visitor(const Visitor & visitor, Variant & operand); template<typename BinaryVisitor, typename Variant1, typename Variant2> typename BinaryVisitor::result_type apply_visitor(BinaryVisitor & visitor, Variant1 & operand1, Variant2 & operand2); template<typename BinaryVisitor, typename Variant1, typename Variant2> typename BinaryVisitor::result_type apply_visitor(const BinaryVisitor & visitor, Variant1 & operand1, Variant2 & operand2); template<typename Visitor> apply_visitor_delayed_t<Visitor> apply_visitor(Visitor & visitor);
Description
The behavior of apply_visitor is dependent on the number of arguments on which it operates (i.e., other than the visitor). The function behaves as follows: Overloads accepting one operand invoke the unary function call operator of the given visitor on the content of the given variant operand.
345
Overloads accepting two operands invoke the binary function call operator of the given visitor on the content of the given variant operands. The overload accepting only a visitor returns a generic function object that accepts either one or two arguments and invokes apply_visitor using these arguments and visitor, thus behaving as specified above. (This behavior is particularly useful, for example, when one needs to operate on each element of a sequence of variant objects using a standard library algorithm.) Returns The overloads acccepting operands return the result of applying the given visitor to the content of the given operands. The overload accepting only a visitor return a function object, thus delaying application of the visitor to any operands. Requires The given visitor must fulfill the StaticVisitor concept requirements with respect to each of the bounded types of the given variant. Throws The overloads accepting operands throw only if the given visitor throws when applied. The overload accepting only a visitor will not throw. (Note, however, that the returned function object may throw when invoked.)
T2, ..., typename TN> T2, ..., typename TN> TN> *); T2, ..., typename TN> T2, ..., typename TN> TN> &);
Class bad_get boost::bad_get The exception thrown in the event of a failed application of boost::get on the given operand value.
Synopsis class bad_get : public std::exception { public: virtual constchar * what() const; };
Function get boost::get Retrieves a value of a specified type from a given variant.
346
Description
The get function allows runtime checked, typesafe retrieval of the content of the given variant. The function succeeds only if the content is of the specified type U, with failure indicated as described below. Warning: After either operand or its content is destroyed (e.g., when the given variant is assigned a value of different type), the returned reference is invalidated. Thus, significant care and caution must be extended when handling the returned reference. Notes As part of its guarantee of typesafety, get enforces constcorrectness. Thus, the specified type U must be constqualified whenever operand or its content is likewise constqualified. The converse, however, is not required: that is, the specified type U may be constqualified even when operand and its content are not. Returns If passed a pointer, get returns a pointer to the value content if it is of the specified type U; otherwise, a null pointer is returned. If passed a reference, get returns a reference to the value content if it is of the specified type U; otherwise, an exception is thrown (see below). Throws Overloads taking a variant pointer will not throw; the overloads taking a variant reference throw bad_get if the content is not of the specified type U. Rationale While visitation via apply_visitor is generally prefered due to its greater safety, get may may be more convenient in some cases due to its straightforward usage.
Class bad_visit boost::bad_visit The exception thrown in the event of a visitor unable to handle the visited value.
Synopsis class bad_visit : public std::exception { public: virtual const char * what() const; };
347
Description
Denotes the intent of the deriving class as meeting the requirements of a static visitor of some type. Also exposes the inner type result_type as required by the StaticVisitor concept. Notes: static_visitor is intended for use as a base type only and is therefore noninstantiable.
348
Adapts the function given at construction for use as a static visitor of type T with result type R.
visitor_ptr_t construct/copy/destruct
1. explicit visitor_ptr_t(R (*)(T) ); Effects Constructs the visitor with the given function.
1.
R operator()(unspecifiedforwardingtype operand); template<typename U> void operator()(const U& );
Effects If passed a value or reference of type T, it invokes the function given at construction, appropriately forwarding operand. Returns Returns the result of the function invocation. Throws The overload taking a value or reference of type T throws if the invoked function throws. The overload taking all other values always throws bad_visit.
Function template visitor_ptr boost::visitor_ptr Returns a visitor object that adapts function pointers for use as a static visitor.
Synopsis template<typename R, typename T> visitor_ptr_t<T,R> visitor_ptr(R (*)(T) );
Description
Constructs and returns a visitor_ptr_t adaptor over the given function. Returns Returns a visitor_ptr_t visitor object that, when applied, invokes the given function. Throws Will not throw. (Note, however, that the returned visitor object may throw when applied.)
4. Design Overview
4.1. "NeverEmpty" Guarantee
4.1.1. The Guarantee All instances v of type variant<T1,T2,...,TN> guarantee that v has constructed content of one of the types Ti, even if an operation on v has previously failed.
349
This implies that variant may be viewed precisely as a union of exactly its bounded types. This "neverempty" property insulates the user from the possibility of undefined variant content and the significant additional complexityofuse attendant with such a possibility. 4.1.2. The Implementation Problem While the neverempty guarantee might at first seem "obvious," it is in fact not even straightforward how to implement it in general (i.e., without unreasonably restrictive additional requirements on bounded types). The central difficulty emerges in the details of variant assignment. Given two instances v1 and v2 of some concrete variant type, there are two distinct, fundamental cases we must consider for the assignment v1 = v2. First consider the case that v1 and v2 each contains a value of the same type. Call this type T. In this situation, assignment is perfectly straightforward: use T::operator=. However, we must also consider the case that v1 and v2 contain values of distinct types. Call these types T and U. At this point, since variant manages its content on the stack, the lefthand side of the assignment (i.e., v1) must destroy its content so as to permit inplace copyconstruction of the content of the righthand side (i.e., v2). In the end, whereas v1 began with content of type T, it ends with content of type U, namely a copy of the content of v2. The crux of the problem, then, is this: in the event that copyconstruction of the content of v2 fails, how can v1 maintain its "neverempty" guarantee? By the time copyconstruction from v2 is attempted, v1 has already destroyed its content! 4.1.3. The "Ideal" Solution: False Hopes Upon learning of this dilemma, clever individuals may propose the following scheme hoping to solve the problem: 1. Provide some "backup" storage, appropriately aligned, capable of holding values of the contained type of the lefthand side. 2. Copy the memory (e.g., using memcpy) of the storage of the lefthand side to the backup storage. 3. Attempt a copy of the righthand side content to the (nowreplicated) lefthand side storage. 4. In the event of an exception from the copy, restore the backup (i.e., copy the memory from the backup storage back into the lefthand side storage). 5. Otherwise, in the event of success, now copy the memory of the lefthand side storage to another "temporary" aligned storage. 6. Now restore the backup (i.e., again copying the memory) to the lefthand side storage; with the "old" content now restored, invoke the destructor of the contained type on the storage of the lefthand side. 7. Finally, copy the memory of the temporary storage to the (nowempty) storage of the lefthand side. While complicated, it appears such a scheme could provide the desired safety in a relatively efficient manner. In fact, several early iterations of the library implemented this very approach. Unfortunately, as Dave Abraham's first noted, the scheme results in undefined behavior: "That's a lot of code to read through, but if it's doing what I think it's doing, it's undefined behavior. "Is the trick to move the bits for an existing object into a buffer so we can tentatively construct a new object in that memory, and later move the old bits back temporarily to destroy the old object? "The standard does not give license to do that: only one object may have a given address at a time. See 3.8, and particularly paragraph 4." Additionally, as close examination quickly reveals, the scheme has the potential to create irreconcilable raceconditions in concurrent environments. Ultimately, even if the above scheme could be made to work on certain platforms with particular compilers, it is still necessary to find a portable solution.
350
4.1.4. An Initial Solution: Double Storage Upon learning of the infeasibility of the above scheme, Anthony Williams proposed in [Wil02] a scheme that served as the basis for a portable solution in some prerelease implementations of variant. The essential idea to this scheme, which shall be referred to as the "double storage" scheme, is to provide enough space within a variant to hold two separate values of any of the bounded types. With the secondary storage, a copy the righthand side can be attempted without first destroying the content of the lefthand side; accordingly, the content of the lefthand side remains available in the event of an exception. Thus, with this scheme, the variant implementation needs only to keep track of which storage contains the content and dispatch any visitation requests, queries, etc. accordingly. The most obvious flaw to this approach is the space overhead incurred. Though some optimizations could be applied in special cases to eliminate the need for double storage for certain bounded types or in some cases entirely (see Section 4.1.6, Enabling Optimizations for more details) many users on the Boost mailing list strongly objected to the use of double storage. In particular, it was noted that the overhead of double storage would be at play at all times even if assignment to variant never occurred. For this reason and others, a new approach was developed. 4.1.5. Current Approach: Temporary Heap Backup Despite the many objections to the double storage solution, it was realized that no replacement would be without drawbacks. Thus, a compromise was desired. To this end, Dave Abrahams suggested to include the following in the behavior specification for variant assignment: "variant assignment from one type to another may incur dynamic allocation." That is, while variant would continue to store its content in situ after construction and after assignment involving identical contained types, variant would store its content on the heap after assignment involving distinct contained types. The algorithm for assignment would proceed as follows: 1. Copyconstruct the content of the righthand side to the heap; call the pointer to this data p. 2. Destroy the content of the lefthand side. 3. Copy p to the lefthand side storage. Since all operations on pointers are nothrow, this scheme would allow variant to meet its neverempty guarantee. The most obvious concern with this approach is that while it certainly eliminates the space overhead of double storage, it introduces the overhead of dynamicallocation to variant assignment not just in terms of the initial allocation but also as a result of the continued storage of the content on the heap. While the former problem is unavoidable, the latter problem may be avoided with the following "temporary heap backup" technique: 1. Copyconstruct the content of the lefthand side to the heap; call the pointer to this data backup. 2. Destroy the content of the lefthand side. 3. Copyconstruct the content of the righthand side in the (nowempty) storage of the lefthand side. 4. In the event of failure, copy backup to the lefthand side storage. 5. In the event of success, deallocate the data pointed to by backup. With this technique: 1) only a single storage is used; 2) allocation is on the heap in the longterm only if the assignment fails; and 3) after any successful assignment, storage within the variant is guaranteed. For the purposes of the initial release of the library, these characteristics were deemed a satisfactory compromise solution. There remain notable shortcomings, however. In particular, there may be some users for which heap allocation must be avoided at all costs; for other users, any allocation may need to occur via a usersupplied allocator. These issues will be addressed in the future (see Section 4.1.7, Future Direction: Policybased Implementation ). For now, though, the library treats storage of its content as an implementation detail. Nonetheless, as described in the next section, there are certain things
351
the user can do to ensure the greatest efficiency for variant instances (see Section 4.1.6, Enabling Optimizations for details). 4.1.6. Enabling Optimizations As described in Section 4.1.2, The Implementation Problem , the central difficulty in implementing the neverempty guarantee is the possibility of failed copyconstruction during variant assignment. Yet types with nothrow copy constructors clearly never face this possibility. Similarly, if one of the bounded types of the variant is nothrow defaultconstructible, then such a type could be used as a safe "fallback" type in the event of failed copy construction. Accordingly, variant is designed to enable the following optimizations once the following criteria on its bounded types are met: For each bounded type T that is nothrow copyconstructible (as indicated by boost::has_nothrow_copy), the library guarantees variant will use only single storage and inplace construction for T. If any bounded type is nothrow defaultconstructible (as indicated by boost::has_nothrow_constructor), the library guarantees variant will use only single storage and inplace construction for every bounded type in the variant. Note, however, that in the event of assignment failure, an unspecified nothrow defaultconstructible bounded type will be defaultconstructed in the lefthand side operand so as to preserve the neverempty guarantee. Caveat: On most platforms, the Type Traits templates has_nothrow_copy and has_nothrow_constructor by default return false for all class and struct types. It is necessary therefore to provide specializations of these templates as appropriate for userdefined types, as demonstrated in the following:
// ...in your code (at file scope)... namespace boost { template <> struct has_nothrow_copy< myUDT > : mpl::true_ { }; }
Implementation Note: So as to make the behavior of variant more predictable in the aftermath of an exception, the current implementation prefers to defaultconstruct boost::blank if specified as a bounded type instead of other nothrow defaultconstructible bounded types. (If this is deemed to be a useful feature, it will become part of the specification for variant; otherwise, it may be obsoleted. Please provide feedback to the Boost mailing list.) 4.1.7. Future Direction: Policybased Implementation As the previous sections have demonstrated, much effort has been expended in an attempt to provide a balance between performance, data size, and heap usage. Further, significant optimizations may be enabled in variant on the basis of certain traits of its bounded types. However, there will be some users for whom the chosen compromise is unsatisfactory (e.g.: heap allocation must be avoided at all costs; if heap allocation is used, custom allocators must be used; etc.). For this reason, a future version of the library will support a policybased implementation of variant. While this will not eliminate the problems described in the previous sections, it will allow the decisions regarding tradeoffs to be decided by the user rather than the library designers.
5. Miscellaneous Notes
352
5.2. Portability
The library aims for 100% ANSI/ISO C++ conformance. However, this is strictly impossible due to the inherently nonportable nature of the Type Traits library's type_with_alignment facility. In practice though, no compilers or platforms have been discovered where this reliance on undefined behavior has been an issue. Additionally, significant effort has been expended to ensure proper functioning despite various compiler bugs and other conformance problems. To date the library testsuite has been compiled and tested successfully on at least the following compilers for basic and advanced functionality: Basic variant<T&> make_variant_over make_recursive_variant Borland C++ 5.5.1 and 5.6.4 Comeau C++ 4.3.0 GNU GCC 3.3.1 GNU GCC 2.95.3 Intel C++ 7.0 Metrowerks CodeWarrior 8.3 Microsoft Visual C++ 7.1 X X X X X X X X X X X X X X X X X X X X X X X
Microsoft Visual C++ 6 SP5 and X 7 Finally, the current state of the testsuite in CVS may be found on the Test Summary page. Please note, however, that this page reports on daytoday changes to interrelease code found in the Boost CVS and thus likely does not match the state of code found in Boost releases.
353
5.3. Troubleshooting
Due to the heavy use of templates in the implementation of variant, it is not uncommon when compiling to encounter problems related to template instantiaton depth, compiler memory, etc. This section attempts to provide advice to common problems experienced on several popular compilers. (This section is still in progress, with additional advice/feedback welcome. Please post to the BoostUsers list with any useful experiences you may have.) 5.3.1. "Template instantiation depth exceeds maximum"
5.3.1.1. GNU GCC
The compiler option ftemplatedepthNN can increase the maximum allowed instantiation depth. (Try ftemplatedepth50.) 5.3.2. "Internal heap limit reached"
5.3.2.1. Microsoft Visual C++
The compiler option /ZmNNN can increase the memory allocation limit. The NNN is a scaling percentage (i.e., 100 denotes the default limit). (Try /Zm200.)
5.4. Acknowledgments
Eric Friedman and Itay Maman designed the initial submission; Eric was the primary implementer. Eric is also the library maintainer and has expanded upon the initial submission adding make_recursive_variant, make_variant_over, support for reference content, etc. Andrei Alexandrescu's work in [Ale01a] and [Ale02] inspired the library's design. Jeff Garland was the formal review manager. Douglas Gregor, Dave Abrahams, Anthony Williams, Fernando Cacciola, Joel de Guzman, Dirk Schreib, Brad King, Giovanni Bajo, Eugene Gladyshev, and others provided helpful feedback and suggestions to refine the semantics, interface, and implementation of the library.
6. References
[Abr00] David Abrahams. "ExceptionSafety in Generic Components." M. Jazayeri, R. Loos, D. Musser (eds.): Generic Programming '98, Proc. of a Dagstuhl Seminar, Lecture Notes on Computer Science, Vol. 1766, pp. 6979. SpringerVerlag Berlin Heidelberg. 2000. [Abr01] David Abrahams. "Error and Exception Handling." Boost technical article. 20012003. [Ale01a] Andrei Alexandrescu. "An Implementation of Discriminated Unions in C++." OOPSLA 2001, Second Workshop on C++ Template Programming. Tampa Bay, 14 October 2001. [Ale01b] Andrei Alexandrescu. Modern C++ Design. AddisonWesley, C++ InDepth series. 2001. [Ale02] Andrei Alexandrescu. "Generic<Programming>: Discriminated Unions" series: Part 1, Part 2, Part 3. C/C++ Users Journal. 2002. [Boo02] Various Boost members. "Proposal A typesafe union." Boost public discussion. 2002.
354
[GoF95] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable ObjectOriented Software. AddisonWesley. 1995. [Gre02] Douglas Gregor. "BOOST_USER: variant." Boost Wiki paper. 2002. MPL Aleksey Gurtovoy. Boost Metaprogramming Library. 2002. [Hen01] Kevlin Henney. Boost Any Library. 2001. Preprocessor Paul Mensonides and Vesa Karvonen. Boost Preprocessor Library. 2002. Type Traits Steve Cleary, Beman Dawes, Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus, John Maddock, Jeremy Siek. Boost Type Traits Library. 2001. [Sut00] Herb Sutter. Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions. AddisonWesley, C++ InDepth series. 2000. [Wil02] Anthony Williams. DoubleStorage Proposal. 2002.
355