├── .gitattributes ├── .gitignore ├── Chapter01 ├── 01_A_program_options_base │ ├── 01_A_program_options_base.pro │ ├── 01_A_program_options_base.pro.user │ └── main.cpp ├── 01_B_program_options_short │ ├── 01_B_program_options_short.pro │ ├── apples_oranges.cfg │ └── main.cpp ├── 02_any │ ├── 02_any.pro │ └── main.cpp ├── 03_variant │ ├── 03_variant.pro │ └── main.cpp ├── 04_A_any_db_example │ ├── 04_A_any_db_example.pro │ └── main.cpp ├── 04_B_variant_db_example │ ├── 04_B_variant_db_example.pro │ └── main.cpp ├── 05_optional │ ├── 05_optional.pro │ └── main.cpp ├── 06_array │ ├── 06_array.pro │ └── main.cpp ├── 07_A_tuple │ ├── 07_A_tuple.pro │ └── main.cpp ├── 07_B_tuple_construction_order │ ├── 07_B_tuple_construction_order.pro │ └── main.cpp ├── 08_bind │ ├── 08_bind.pro │ └── main.cpp ├── 09_type_index │ ├── 09_type_index.pro │ └── main.cpp ├── 10_A_move │ ├── 10_A_move.pro │ └── main.cpp ├── 10_B_move_c++11 │ └── 10_B_move_c++11.pro ├── 11_noncopyable │ ├── 11_noncopyable.pro │ └── main.cpp ├── 12_A_noncopyable_movable │ ├── 12_A_noncopyable_movable.pro │ └── main.cpp ├── 12_B_noncopyable_movable_c++11 │ └── 12_B_noncopyable_movable_c++11.pro ├── 13_algorithm │ ├── 13_algorithm.pro │ └── main.cpp ├── Chapter01.pro └── build-01_A_program_options_base-Desktop_Qt_5_9_1_MinGW_32bit-Debug │ ├── .qmake.stash │ ├── Makefile │ ├── Makefile.Debug │ └── Makefile.Release ├── Chapter02 ├── 01_scoped_ptr │ ├── 01_scoped_ptr.pro │ └── main.cpp ├── 02_shared_ptr │ ├── 02_shared_ptr.pro │ └── main.cpp ├── 03_scoped_array │ ├── 03_scoped_array.pro │ └── main.cpp ├── 04_shared_array │ ├── 04_shared_array.pro │ └── main.cpp ├── 05_function_fobject │ ├── 05_function_fobject.pro │ └── main.cpp ├── 06_function_fpointer │ ├── 06_function_fpointer.pro │ └── main.cpp ├── 07_function_lambda_c++11 │ ├── 07_function_lambda_c++11.pro │ └── main.cpp ├── 08_ptr_container_c++11 │ ├── 08_ptr_container_c++11.pro │ └── main.cpp ├── 09_scope_exit │ ├── 09_scope_exit.pro │ └── main.cpp ├── 10_base_from_member │ ├── 10_base_from_member.pro │ └── main.cpp └── Chapter02.pro ├── Chapter03 ├── 01_lexical_to_number │ ├── 01_lexical_to_number.pro │ └── main.cpp ├── 02_lexical_to_string │ ├── 02_lexical_to_string.pro │ └── main.cpp ├── 03_numeric_cast │ ├── 03_numeric_cast.pro │ └── main.cpp ├── 04_lexical_user_defined │ ├── 04_lexical_user_defined.pro │ └── main.cpp ├── 05_polymorphic_cast │ ├── 05_polymorphic_cast.pro │ └── main.cpp ├── 06_spirit │ ├── 06_spirit.pro │ └── main.cpp ├── 07_spirit_rules │ ├── 07_spirit_rules.pro │ └── main.cpp └── Chapter03.pro ├── Chapter04 ├── Chapter04.pro ├── conditional │ ├── 8341_Article.html │ ├── 8341_Article.xml │ ├── conditional.pro │ └── main.cpp ├── disable_if_c │ ├── disable_if_c.pro │ └── main.cpp ├── enable_if_c │ ├── enable_if_c.pro │ └── main.cpp ├── is_stdvector │ ├── is_stdvector.pro │ └── main.cpp ├── mpl_int_ │ ├── main.cpp │ └── mpl_int_.pro ├── static_assert │ ├── main.cpp │ └── static_assert.pro └── typeof │ ├── main.cpp │ └── typeof.pro ├── Chapter05 ├── Chapter05.pro ├── atomics │ ├── atomics.pro │ └── main.cpp ├── interruptions │ ├── interruptions.pro │ └── main.cpp ├── mutex │ ├── main.cpp │ └── mutex.pro ├── shared_lock │ ├── main.cpp │ └── shared_lock.pro ├── thread │ ├── main.cpp │ └── thread.pro ├── thread_group │ ├── main.cpp │ └── thread_group.pro ├── thread_specific_ptr │ ├── main.cpp │ └── thread_specific_ptr.pro └── work_queue │ ├── main.cpp │ └── work_queue.pro ├── Chapter06 ├── Chapter06.pro ├── conveyor │ ├── conveyor.pro │ └── main.cpp ├── exception_ptr │ ├── exception_ptr.pro │ └── main.cpp ├── nonblocking_barrier │ ├── main.cpp │ └── nonblocking_barrier.pro ├── tasks_processor_base │ ├── main.cpp │ ├── tasks_processor_base.hpp │ └── tasks_processor_base.pro ├── tasks_processor_multithread │ ├── main.cpp │ ├── tasks_processor_multithread.hpp │ └── tasks_processor_multithread.pro ├── tasks_processor_network │ ├── main.cpp │ ├── tasks_processor_network.hpp │ └── tasks_processor_network.pro ├── tasks_processor_signals │ ├── main.cpp │ ├── tasks_processor_signals.hpp │ └── tasks_processor_signals.pro └── tasks_processor_timers │ ├── main.cpp │ ├── tasks_processor_timers.hpp │ └── tasks_processor_timers.pro ├── Chapter07 ├── Chapter07.pro ├── case_conv │ ├── case_conv.pro │ └── main.cpp ├── format │ ├── format.pro │ └── main.cpp ├── iterator_range │ ├── iterator_range.pro │ └── main.cpp ├── regex_match │ ├── main.cpp │ └── regex_match.pro ├── regex_replace │ ├── main.cpp │ └── regex_replace.pro ├── string_algo │ ├── main.cpp │ └── string_algo.pro └── string_ref │ ├── main.cpp │ └── string_ref.pro ├── Chapter08 ├── Chapter08.pro ├── higher_order_metafunctions │ ├── higher_order_metafunctions.pro │ └── main.cpp ├── lazy │ ├── lazy.pro │ └── main.cpp ├── manipulating_vector_of_types │ ├── main.cpp │ └── manipulating_vector_of_types.pro ├── result_of_c++11 │ ├── main.cpp │ └── result_of_c++11.pro ├── splitting_tuple │ ├── main.cpp │ └── splitting_tuple.pro ├── tuple_to_string │ ├── main.cpp │ └── tuple_to_string.pro └── vector_of_types │ ├── main.cpp │ └── vector_of_types.pro ├── Chapter09 ├── Chapter09.pro ├── bimap │ ├── bimap.pro │ └── main.cpp ├── flat │ ├── flat.pro │ └── main.cpp ├── hash │ ├── hash.pro │ └── main.cpp ├── multiindex │ ├── main.cpp │ └── multiindex.pro ├── slist_and_pool │ ├── main.cpp │ └── slist_and_pool.pro └── unordered │ ├── main.cpp │ └── unordered.pro ├── Chapter10 ├── Chapter10.pro ├── constexpr_c++11 │ ├── constexpr_c++11.pro │ └── main.cpp ├── export_import │ ├── export_import.pro │ └── main.cpp ├── extern_template │ ├── extern_template.pro │ ├── header.hpp │ ├── main.cpp │ └── source.cpp ├── int128 │ ├── int128.pro │ └── main.cpp ├── my_library │ ├── my_library.cpp │ ├── my_library.hpp │ └── my_library.pro ├── no_rtti │ ├── main.cpp │ └── no_rtti.pro ├── noexcept_c++11 │ ├── main.cpp │ └── noexcept_c++11.pro └── version │ ├── main.cpp │ └── version.pro ├── Chapter11 ├── Chapter11.pro ├── coroutines │ ├── coroutines.pro │ └── main.cpp ├── erasing_files │ ├── erasing_files.pro │ └── main.cpp ├── interprocess_basics │ ├── interprocess_basics.pro │ └── main.cpp ├── interprocess_pointers │ ├── interprocess_pointers.pro │ └── main.cpp ├── interprocess_queue │ ├── interprocess_queue.pro │ └── main.cpp ├── listing_files │ ├── listing_files.pro │ └── main.cpp └── reading_files │ ├── main.cpp │ └── reading_files.pro ├── Chapter12 ├── Chapter12.pro ├── gil │ ├── gil.pro │ └── main.cpp ├── graph │ ├── graph.pro │ └── main.cpp ├── graph_vis │ ├── graph_vis.pro │ └── main.cpp ├── math │ ├── main.cpp │ └── math.pro ├── random │ ├── main.cpp │ └── random.pro ├── testing │ ├── main.cpp │ └── testing.pro └── testing_advanced │ ├── developer1.cpp │ ├── developer2.cpp │ ├── foo.cpp │ ├── foo.hpp │ ├── main.cpp │ └── testing_advanced.pro ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Chapter01/01_A_program_options_base/01_A_program_options_base.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | LIBS += -lboost_program_options 6 | 7 | SOURCES += main.cpp 8 | 9 | -------------------------------------------------------------------------------- /Chapter01/01_A_program_options_base/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace opt = boost::program_options; 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | // Constructing an options describing variable and giving it a 9 | // textual description "All options" 10 | opt::options_description desc("All options"); 11 | 12 | // When we are adding options, first parameter is a name 13 | // to be used in command line. Second parameter is a type 14 | // of that option, wrapped in value<> class. Third parameter 15 | // must be a short description of that option. 16 | desc.add_options() 17 | ("apples", opt::value(), "how many apples do you have") 18 | ("oranges", opt::value(), "how many oranges do you have") 19 | ("help", "produce help message") 20 | ; 21 | 22 | // Variable to store our command line arguments 23 | opt::variables_map vm; 24 | 25 | // Parsing and storing arguments 26 | opt::store(opt::parse_command_line(argc, argv, desc), vm); 27 | 28 | // Must be called after all the parsing and storing 29 | opt::notify(vm); 30 | 31 | if (vm.count("help")) { 32 | std::cout << desc << "\n"; 33 | return 1; 34 | } 35 | 36 | std::cout << "Fruits count: " 37 | << vm["apples"].as() + vm["oranges"].as() 38 | << std::endl; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/01_B_program_options_short.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | LIBS += -lboost_program_options 6 | 7 | SOURCES += main.cpp 8 | 9 | include(apples_oranges.cfg) 10 | 11 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/apples_oranges.cfg: -------------------------------------------------------------------------------- 1 | # This is a comment in config file example 2 | 3 | oranges=20 4 | #apples=10 5 | #name=Reader 6 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace opt = boost::program_options; 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | opt::options_description desc("All options"); 9 | 10 | int oranges_var = 0; 11 | desc.add_options() 12 | // ProgramOptions library stores the option value into the variable that 13 | // is passed by pointer. Here value of "--oranges" option will be 14 | // stored into 'oranges_var'. 15 | ("oranges,o", opt::value(&oranges_var)->required(), "oranges that you have") 16 | 17 | // 'name' option is not marked with 'required()', so user may not provide it. 18 | ("name", opt::value(), "your name") 19 | 20 | // 'a' is a short option name for apples. Just out '-a 10' 21 | // If no value provided for 'apples', the the default value is used. 22 | ("apples,a", opt::value()->default_value(10), "apples that you have") 23 | ("help", "produce help message") 24 | ; 25 | 26 | opt::variables_map vm; 27 | 28 | // Parsing command line options and storing values to 'vm' 29 | opt::store(opt::parse_command_line(argc, argv, desc), vm); 30 | 31 | // We can also parse environment variables using 'parse_environment' method 32 | 33 | if (vm.count("help")) { 34 | std::cout << desc << "\n"; 35 | return 1; 36 | } 37 | 38 | // Adding missing options from "apples_oranges.cfg" config file. 39 | try { 40 | opt::store(opt::parse_config_file("apples_oranges.cfg", desc), vm); 41 | } catch (const opt::reading_file& e) { 42 | std::cout << "Error: " << e.what() << std::endl; 43 | } 44 | 45 | try { 46 | // `opt::required_option` exception is thrown if 47 | // one of the required options was not set. 48 | opt::notify(vm); 49 | 50 | } catch (const opt::required_option& e) { 51 | std::cout << "Error: " << e.what() << std::endl; 52 | return 2; 53 | } 54 | 55 | if (vm.count("name")) { 56 | std::cout << "Hi," << vm["name"].as() << "!\n"; 57 | } 58 | std::cout << "Fruits count: " 59 | << vm["apples"].as() + vm["oranges"].as() 60 | << std::endl; 61 | } 62 | -------------------------------------------------------------------------------- /Chapter01/02_any/02_any.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter01/02_any/main.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | //#include 3 | //#include 4 | //#include 5 | 6 | //int main() 7 | //{ 8 | 9 | // typedef std::auto_ptr object_ptr; 10 | // std::vector some_values; 11 | // some_values.push_back(new Object(10)); 12 | // some_values.push_back(new Object("Hello there")); 13 | // some_values.push_back(new Object(std::string("Wow!"))); 14 | 15 | // std::string* p = dynamic_cast(some_values.back().get()); 16 | // assert(p); 17 | // (*p) += " That is great!\n"; 18 | // std::cout << *p; 19 | 20 | // return 0; 21 | //} 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | int main() { 29 | std::vector some_values; 30 | some_values.push_back(10); 31 | const char* c_str = "Hello there!"; 32 | some_values.push_back(c_str); 33 | some_values.push_back(std::string("Wow!")); 34 | 35 | std::string& s = boost::any_cast(some_values.back()); 36 | s += " That is great!\n"; 37 | std::cout << s; 38 | } 39 | 40 | void example_func() { 41 | boost::any variable(std::string("Hello world!")); 42 | 43 | // Following method may throw a boost::bad_any_cast exception 44 | // if actual value in variable is not a std::string 45 | std::string s1 = boost::any_cast(variable); 46 | 47 | // Never throws. If actual value in variable is not a std::string 48 | // will return an NULL pointer. 49 | std::string* s2 = boost::any_cast(&variable); 50 | 51 | 52 | (void)s2; // Supressing warnings about unused variable 53 | (void)s1; 54 | } 55 | -------------------------------------------------------------------------------- /Chapter01/03_variant/03_variant.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/03_variant/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | typedef boost::variant my_var_t; 8 | std::vector some_values; 9 | some_values.push_back(10); 10 | some_values.push_back("Hello there!"); 11 | some_values.push_back(std::string("Wow!")); 12 | 13 | std::string& s = boost::get(some_values.back()); 14 | s += " That is great!\n"; 15 | std::cout << s; 16 | } 17 | 18 | 19 | 20 | void example_func() { 21 | // Default constructor will construct an instance of boost::blank 22 | boost::variant var; 23 | 24 | // 'which()' method returns an index of a type currently held by variant. 25 | assert(var.which() == 0); // Empty state 26 | 27 | var = "Hello, dear reader"; 28 | assert(var.which() != 0); 29 | } 30 | 31 | void example_func1() { 32 | boost::variant variable(0); 33 | 34 | // Following method may throw a boost::bad_get 35 | // exception if actual value in variable is not an int 36 | int s1 = boost::get(variable); 37 | 38 | // If actual value in variable is not an int will return an NULL pointer. 39 | int* s2 = boost::get(&variable); 40 | 41 | 42 | (void)s1; // Supressing warnings about unused variable 43 | (void)s2; // Supressing warnings about unused variable 44 | } 45 | -------------------------------------------------------------------------------- /Chapter01/04_A_any_db_example/04_A_any_db_example.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/04_A_any_db_example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // This typedefs and methods will be in our header, 9 | // that wraps around native SQL interface 10 | typedef boost::any cell_t; 11 | typedef std::vector db_row_t; 12 | 13 | // This is just an example, no actual work with database. 14 | db_row_t get_row(const char* /*query*/) { 15 | // In real application 'query' parameter shall have a 'const 16 | // char*' or 'const std::string&' type? See recipe "Type 17 | // 'reference to string'" for an answer. 18 | db_row_t row; 19 | row.push_back(10); 20 | row.push_back(10.1f); 21 | row.push_back(std::string("hello again")); 22 | return row; 23 | } 24 | 25 | // This is how a user will use your classes 26 | struct db_sum: public std::unary_function { 27 | private: 28 | double& sum_; 29 | 30 | public: 31 | explicit db_sum(double& sum) 32 | : sum_(sum) 33 | {} 34 | 35 | void operator()(const cell_t& value) { 36 | const std::type_info& ti = value.type(); 37 | if (ti == typeid(int)) { 38 | sum_ += boost::any_cast(value); 39 | } else if (ti == typeid(float)) { 40 | sum_ += boost::any_cast(value); 41 | } 42 | } 43 | }; 44 | 45 | int main() { 46 | db_row_t row = get_row("Query: Give me some row, please."); 47 | double res = 0.0; 48 | std::for_each(row.begin(), row.end(), db_sum(res)); 49 | std::cout << "Sum of arithmetic types in database row is: " << res << std::endl; 50 | } 51 | -------------------------------------------------------------------------------- /Chapter01/04_B_variant_db_example/04_B_variant_db_example.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/04_B_variant_db_example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // This typedefs and methods will be in header, 7 | // that wraps around native SQL interface. 8 | typedef boost::variant cell_t; 9 | typedef std::vector db_row_t; 10 | 11 | // This is just an example, no actual work with database. 12 | db_row_t get_row(const char* /*query*/) { 13 | // See recipe "Type 'reference to string'" 14 | // for a better type for 'query' parameter. 15 | db_row_t row; 16 | row.push_back(10); 17 | row.push_back(10.1f); 18 | row.push_back("hello again"); 19 | return row; 20 | } 21 | 22 | // This is how code required to sum values 23 | // We can provide no template parameter 24 | // to boost::static_visitor<> if our visitor returns nothing. 25 | struct db_sum_visitor: public boost::static_visitor { 26 | double operator()(int value) const { 27 | return value; 28 | } 29 | double operator()(float value) const { 30 | return value; 31 | } 32 | double operator()(const std::string& /*value*/) const { 33 | return 0.0; 34 | } 35 | }; 36 | 37 | int main() { 38 | db_row_t row = get_row("Query: Give me some row, please."); 39 | double res = 0.0; 40 | for (db_row_t::const_iterator it = row.begin(), end = row.end(); it != end; ++it) { 41 | res += boost::apply_visitor(db_sum_visitor(), *it); 42 | } 43 | std::cout << "Sum of arithmetic types in database row is: " << res << std::endl; 44 | } 45 | -------------------------------------------------------------------------------- /Chapter01/05_optional/05_optional.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter01/05_optional/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class locked_device { 6 | explicit locked_device(const char* /*param*/) { 7 | // We have unique access to device 8 | std::cout << "Device is locked\n"; 9 | } 10 | 11 | public: 12 | ~locked_device () { 13 | // Releasing device lock 14 | } 15 | 16 | void use() { 17 | std::cout << "Success!\n"; 18 | } 19 | 20 | static boost::optional try_lock_device() { 21 | if (rand()%2) { 22 | // Failed to lock device 23 | return boost::none; 24 | } 25 | // Success! 26 | return locked_device("device name"); 27 | } 28 | }; 29 | 30 | int main() { 31 | // Boost has a library called Random. If you wonder why it was 32 | // written when stdlib.h has rand() function, see recipes 33 | // 'Random distribution' and 'Making a random generator'. 34 | srandom(5); 35 | 36 | for (unsigned i = 0; i < 10; ++i) { 37 | boost::optional t = locked_device::try_lock_device(); 38 | // optional is convertible to bool 39 | if (t) { 40 | t->use(); 41 | return 0; 42 | } else { 43 | std::cout << "...trying again\n"; 44 | } 45 | } 46 | 47 | std::cout << "Failure!\n"; 48 | return -1; 49 | } 50 | -------------------------------------------------------------------------------- /Chapter01/06_array/06_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/06_array/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef boost::array array4_t; 5 | 6 | array4_t& vector_advance(array4_t& val) { 7 | // C++11 lambda function 8 | const auto inc = [](char& c){ ++c; }; 9 | 10 | // boost::array has begin(), cbegin(), end(), cend(), 11 | // rbegin(), size(), empty() and other functions that are 12 | // common for STL containers. 13 | std::for_each(val.begin(), val.end(), inc); 14 | return val; 15 | } 16 | 17 | int main() { 18 | // We can initialize boost::array just like an array in C++11: 19 | // array4_t val = {0, 1, 2, 3}; 20 | // but in C++03 additional pair of curly brackets is required. 21 | array4_t val = {{0, 1, 2, 3}}; 22 | 23 | array4_t val_res; // it is default constructible 24 | val_res = vector_advance(val); // it is assignable 25 | 26 | assert(val.size() == 4); 27 | assert(val[0] == 1); 28 | /*val[4];*/ // Will trigger an assert because max index is 3 29 | 30 | // We can make this assert work at compile-time. 31 | // Interested? See recipe 'Check sizes at compile-time' 32 | assert(sizeof(val) == sizeof(char) * array4_t::static_size); 33 | } 34 | -------------------------------------------------------------------------------- /Chapter01/07_A_tuple/07_A_tuple.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/07_A_tuple/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void foo1() { 9 | boost::tuple almost_a_pair(10, "Hello"); 10 | boost::tuple quad(10, 1.0f, 10.0, 1); 11 | 12 | 13 | int i = boost::get<0>(almost_a_pair); 14 | const std::string& str = boost::get<1>(almost_a_pair); 15 | double d = boost::get<2>(quad); 16 | 17 | (void) i; 18 | (void) str; 19 | (void) d; 20 | 21 | // Tuple comparison operators are 22 | // defined in header "boost/tuple/tuple_comparison.hpp" 23 | // Don't forget to include it! 24 | std::set > s; 25 | s.insert(boost::make_tuple(1, 1.0, 2)); 26 | s.insert(boost::make_tuple(2, 10.0, 2)); 27 | s.insert(boost::make_tuple(3, 100.0, 2)); 28 | } 29 | 30 | void foo2() { 31 | #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS 32 | // Requires C++11 33 | const auto t = boost::make_tuple(0, -1.0, 2); 34 | assert(2 == boost::get<2>(t)); 35 | // We can make a compile time assert for type 36 | // of t. Interested? See chapter 'Compile time tricks' 37 | #endif 38 | } 39 | 40 | void foo3() { 41 | boost::tuple quad(10, 1.0f, 10.0, 1); 42 | int i; 43 | float f; 44 | double d; 45 | int i2; 46 | 47 | // Passing values from 'quad' variables 48 | // to variables 'i', 'f', 'd', 'i2' 49 | boost::tie(i, f, d, i2) = quad; 50 | 51 | assert(i == 10); 52 | assert(i2 == 1); 53 | } 54 | 55 | struct id_name_pair { 56 | int id; 57 | std::string name; 58 | }; 59 | 60 | int main () { 61 | foo1(); 62 | foo2(); 63 | foo3(); 64 | } 65 | -------------------------------------------------------------------------------- /Chapter01/07_B_tuple_construction_order/07_B_tuple_construction_order.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/07_B_tuple_construction_order/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct printer { 6 | printer() { std::cout << I; } 7 | }; 8 | 9 | int main() { 10 | // Outputs 012 11 | boost::tuple, printer<1>, printer<2> > t; 12 | (void)t; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter01/08_bind/08_bind.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/08_bind/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void test1() { 9 | boost::array v = {{1, 2, 3, 4, 5, 6, 7, 100, 99, 98, 97, 96}}; 10 | 11 | const std::size_t count0 = std::count_if(v.begin(), v.end(), [](int x) { 12 | return 5 < x ; 13 | }); 14 | const std::size_t count1 = std::count_if(v.begin(), v.end(), 15 | boost::bind(std::less(), 5, _1) 16 | ); 17 | assert(count0 == count1); 18 | } 19 | 20 | void test2() { 21 | boost::array v = {{"We ", "are", " the champions!"}}; 22 | 23 | const std::size_t count0 = std::count_if(v.begin(), v.end(), [](const std::string& s) { 24 | return s.empty(); 25 | }); 26 | const std::size_t count1 = std::count_if(v.begin(), v.end(), 27 | boost::bind(&std::string::empty, _1) 28 | ); 29 | assert(count0 == count1); 30 | } 31 | 32 | void test3() { 33 | boost::array v = {{"We ", "are", " the champions!"}}; 34 | 35 | const std::size_t count0 = std::count_if(v.begin(), v.end(), 36 | [](const std::string& s) { return s.size() < 5; } 37 | ); 38 | const std::size_t count1 = std::count_if(v.begin(), v.end(), 39 | boost::bind( 40 | std::less(), 41 | boost::bind(&std::string::size, _1), 42 | 5 43 | ) 44 | ); 45 | assert(count0 == count1); 46 | } 47 | 48 | void test4() { 49 | boost::array v = {{"We ", "are", " the champions!"}}; 50 | std::string s("Expensive copy constructor is called when binding"); 51 | 52 | const std::size_t count0 = std::count_if(v.begin(), v.end(), 53 | [&s](const std::string& x) { return x < s; } 54 | ); 55 | const std::size_t count1 = std::count_if(v.begin(), v.end(), 56 | boost::bind(std::less(), _1, s) 57 | ); 58 | assert(count0 == count1); 59 | } 60 | 61 | 62 | #include 63 | 64 | void test5() { 65 | boost::array v = {{"We ", "are", " the champions!"}}; 66 | std::string s("Expensive copy constructor is NOT called when binding"); 67 | 68 | const std::size_t count1 = std::count_if(v.begin(), v.end(), 69 | boost::bind(std::less(), _1, boost::cref(s)) 70 | ); 71 | 72 | 73 | 74 | const std::size_t count0 = std::count_if(v.begin(), v.end(), [&s](const std::string& x) { 75 | return x < s; 76 | }); 77 | assert(count0 == count1); 78 | }; 79 | 80 | void test6() { 81 | const auto twice = boost::bind(std::plus(), _1, _1); 82 | assert(twice(2) == 4); 83 | 84 | const auto minus_from_second = boost::bind(std::minus(), _2, _1); 85 | assert(minus_from_second(2, 4) == 2); 86 | 87 | const auto sum_second_and_third = boost::bind(std::plus(), _2, _3); 88 | assert(sum_second_and_third(10, 20, 30) == 50); 89 | } 90 | 91 | 92 | int main () { 93 | test1(); 94 | test2(); 95 | test3(); 96 | test4(); 97 | test5(); 98 | test6(); 99 | } 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Chapter01/09_type_index/09_type_index.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/09_type_index/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void do_something(const T& x) { 6 | std::cout << "T is " << typeid(T).name() << std::endl; 7 | 8 | (void)x; 9 | } 10 | 11 | 12 | void test1() { 13 | auto&& x = 42; 14 | std::cout << "x is " 15 | << typeid(decltype(x)).name() 16 | << std::endl; 17 | 18 | (void)x; 19 | } 20 | 21 | #include 22 | #include 23 | namespace bti = boost::typeindex; 24 | 25 | template 26 | void do_something_again(const T& x) { 27 | std::cout << "T is " << boost::typeindex::type_id() << std::endl; 28 | 29 | (void)x; 30 | } 31 | 32 | 33 | void test2() { 34 | auto&& x = 42; 35 | std::cout << "x is " 36 | << boost::typeindex::type_id_with_cvr() 37 | << std::endl; 38 | 39 | (void)x; 40 | } 41 | 42 | 43 | int main () { 44 | do_something(1.0); 45 | test1(); 46 | do_something_again(1.0); 47 | test2(); 48 | } 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Chapter01/10_A_move/10_A_move.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/10_A_move/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | namespace other { 11 | class characteristics{}; 12 | } 13 | 14 | struct person_info { 15 | std::string name_; 16 | std::string second_name_; 17 | other::characteristics characteristic_; 18 | 19 | // Fields declared here 20 | // ... 21 | private: 22 | BOOST_COPYABLE_AND_MOVABLE(person_info) 23 | public: 24 | // For the simplicity of example we will assume that 25 | // person_info default constructor and swap are very 26 | // fast/cheap to call 27 | person_info() {} 28 | 29 | person_info(const person_info& p) 30 | : name_(p.name_) 31 | , second_name_(p.second_name_) 32 | , characteristic_(p.characteristic_) 33 | {} 34 | 35 | person_info(BOOST_RV_REF(person_info) person) { 36 | swap(person); 37 | } 38 | 39 | person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) { 40 | person_info tmp(person); 41 | swap(tmp); 42 | return *this; 43 | } 44 | 45 | person_info& operator=(BOOST_RV_REF(person_info) person) { 46 | person_info tmp(boost::move(person)); 47 | swap(tmp); 48 | return *this; 49 | } 50 | 51 | void swap(person_info& rhs); 52 | }; 53 | 54 | 55 | #include 56 | 57 | void person_info::swap(person_info& rhs) { 58 | name_.swap(rhs.name_); 59 | second_name_.swap(rhs.second_name_); 60 | boost::swap(characteristic_, rhs.characteristic_); 61 | } 62 | 63 | 64 | 65 | int main() { 66 | 67 | person_info vasya; 68 | vasya.name_ = "Vasya"; 69 | vasya.second_name_ = "Snow"; 70 | 71 | person_info new_vasya(boost::move(vasya)); 72 | assert(new_vasya.name_ == "Vasya"); 73 | assert(new_vasya.second_name_ == "Snow"); 74 | assert(vasya.name_.empty()); 75 | assert(vasya.second_name_.empty()); 76 | 77 | vasya = boost::move(new_vasya); 78 | assert(vasya.name_ == "Vasya"); 79 | assert(vasya.second_name_ == "Snow"); 80 | assert(new_vasya.name_.empty()); 81 | assert(new_vasya.second_name_.empty()); 82 | 83 | new_vasya = vasya; 84 | assert(vasya.name_ == "Vasya"); 85 | assert(vasya.second_name_ == "Snow"); 86 | assert(new_vasya.name_ == "Vasya"); 87 | assert(new_vasya.second_name_ == "Snow"); 88 | } 89 | -------------------------------------------------------------------------------- /Chapter01/10_B_move_c++11/10_B_move_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += ../10_A_move/main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/11_noncopyable/11_noncopyable.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/11_noncopyable/main.cpp: -------------------------------------------------------------------------------- 1 | class descriptor_owner { 2 | void* descriptor_; 3 | 4 | public: 5 | explicit descriptor_owner(const char* params); 6 | 7 | ~descriptor_owner() { 8 | // system_api_free_descriptor(descriptor_); 9 | } 10 | }; 11 | 12 | descriptor_owner::descriptor_owner(const char* ){} 13 | 14 | 15 | void foo() { 16 | descriptor_owner d1("O_o"); 17 | descriptor_owner d2("^_^"); 18 | 19 | // Descriptor of d2 was not correctly freed 20 | d2 = d1; 21 | 22 | // destructor of d2 will free the descriptor 23 | // destructor of d1 will try to free already freed descriptor 24 | } 25 | 26 | #include 27 | 28 | class descriptor_owner_fixed : private boost::noncopyable { 29 | // ... 30 | public: 31 | descriptor_owner_fixed(const char* params){ (void)params; } 32 | }; 33 | 34 | void foo2() { 35 | descriptor_owner_fixed d1("O_o"); 36 | descriptor_owner_fixed d2("^_^"); 37 | 38 | // Won't compile 39 | //d2 = d1; 40 | //descriptor_owner_fixed d3(d1); 41 | } 42 | 43 | struct noncopyable_or_not { 44 | private: 45 | noncopyable_or_not(const noncopyable_or_not&); 46 | noncopyable_or_not& operator=(const noncopyable_or_not&); 47 | 48 | public: 49 | noncopyable_or_not(){} 50 | noncopyable_or_not(noncopyable_or_not&){} 51 | noncopyable_or_not& operator=(noncopyable_or_not&){ return *this; } 52 | }; 53 | 54 | struct noncopyable_or_not2 { 55 | private: 56 | noncopyable_or_not2(noncopyable_or_not2&); 57 | noncopyable_or_not2& operator=(noncopyable_or_not2&); 58 | 59 | public: 60 | noncopyable_or_not2(){} 61 | noncopyable_or_not2(const noncopyable_or_not2&){} 62 | noncopyable_or_not2& operator=(const noncopyable_or_not2&) { return *this; } 63 | }; 64 | 65 | int main() 66 | { 67 | foo(); 68 | foo2(); 69 | 70 | noncopyable_or_not non1; 71 | noncopyable_or_not non2 = non1; 72 | 73 | const noncopyable_or_not2 n1; 74 | noncopyable_or_not2 n2 = n1; 75 | 76 | // Supressing warnings about unused variables 77 | (void)non2; 78 | (void) n2; 79 | 80 | return 0; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /Chapter01/12_A_noncopyable_movable/12_A_noncopyable_movable.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP03FLAG 7 | -------------------------------------------------------------------------------- /Chapter01/12_B_noncopyable_movable_c++11/12_B_noncopyable_movable_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += ../12_A_noncopyable_movable/main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/13_algorithm/13_algorithm.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/13_algorithm/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | boost::array chars_65_125_pre11() { 4 | boost::array res; 5 | 6 | const unsigned char offset = 65; 7 | for (std::size_t i = 0; i < res.size(); ++i) { 8 | res[i] = i + offset; 9 | } 10 | 11 | return res; 12 | } 13 | 14 | 15 | #include 16 | #include 17 | 18 | boost::array chars_65_125() { 19 | boost::array res; 20 | boost::algorithm::iota(res.begin(), res.end(), 65); 21 | return res; 22 | } 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | void to_hex_test1() { 29 | const std::string data = "Hello word"; 30 | boost::algorithm::hex( 31 | data.begin(), data.end(), 32 | std::ostream_iterator(std::cout) 33 | ); 34 | 35 | std::cout << '\n'; 36 | } 37 | 38 | void to_hex_test2() { 39 | const std::string data = "Hello word"; 40 | boost::algorithm::hex( 41 | data, 42 | std::ostream_iterator(std::cout) 43 | ); 44 | 45 | std::cout << '\n'; 46 | } 47 | 48 | #include 49 | int main() { 50 | assert(chars_65_125_pre11() == chars_65_125()); 51 | to_hex_test1(); 52 | to_hex_test2(); 53 | } 54 | -------------------------------------------------------------------------------- /Chapter01/Chapter01.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_A_program_options_base \ 5 | 01_B_program_options_short \ 6 | 02_any \ 7 | 03_variant \ 8 | 04_A_any_db_example \ 9 | 04_B_variant_db_example \ 10 | 05_optional \ 11 | 06_array \ 12 | 07_A_tuple \ 13 | 07_B_tuple_construction_order \ 14 | 08_bind \ 15 | 09_type_index \ 16 | 10_A_move \ 17 | 10_B_move_c++11 \ 18 | 11_noncopyable \ 19 | 12_A_noncopyable_movable \ 20 | 12_B_noncopyable_movable_c++11 \ 21 | 13_algorithm 22 | 23 | -------------------------------------------------------------------------------- /Chapter01/build-01_A_program_options_base-Desktop_Qt_5_9_1_MinGW_32bit-Debug/.qmake.stash: -------------------------------------------------------------------------------- 1 | QMAKE_CXX.INCDIRS = \ 2 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include \ 3 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0/include-fixed \ 4 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include \ 5 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++ \ 6 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/i686-w64-mingw32 \ 7 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/include/c++/backward 8 | QMAKE_CXX.LIBDIRS = \ 9 | C:/Qt/Tools/mingw530_32/lib/gcc/i686-w64-mingw32/5.3.0 \ 10 | C:/Qt/Tools/mingw530_32/lib/gcc \ 11 | C:/Qt/Tools/mingw530_32/i686-w64-mingw32/lib \ 12 | C:/Qt/Tools/mingw530_32/lib 13 | QMAKE_CXX.QT_COMPILER_STDCXX = 199711L 14 | QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 5 15 | QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 3 16 | QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 17 | QMAKE_CXX.COMPILER_MACROS = \ 18 | QT_COMPILER_STDCXX \ 19 | QMAKE_GCC_MAJOR_VERSION \ 20 | QMAKE_GCC_MINOR_VERSION \ 21 | QMAKE_GCC_PATCH_VERSION 22 | -------------------------------------------------------------------------------- /Chapter02/01_scoped_ptr/01_scoped_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/01_scoped_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | class foo_class { 3 | public: 4 | char data[100000000]; 5 | 6 | explicit foo_class(const char* /*param*/){} 7 | }; 8 | 9 | bool g_exit_on_first_function = true; 10 | bool some_function1(foo_class* /*param*/) { 11 | return g_exit_on_first_function; 12 | } 13 | 14 | void some_function2(foo_class* /*param*/) { 15 | throw std::exception(); 16 | } 17 | 18 | bool foo1() { 19 | foo_class* p = new foo_class("Some initialization data"); 20 | 21 | const bool something_else_happened = some_function1(p); 22 | if (something_else_happened) { 23 | delete p; 24 | return false; 25 | } 26 | 27 | some_function2(p); 28 | delete p; 29 | return true; 30 | } 31 | 32 | bool foo2() { 33 | foo_class* p = new foo_class("Some initialization data"); 34 | try { 35 | const bool something_else_happened = some_function1(p); 36 | if (something_else_happened) { 37 | delete p; 38 | return false; 39 | } 40 | 41 | some_function2(p); 42 | } catch (...) { 43 | delete p; 44 | throw; 45 | } 46 | 47 | delete p; 48 | return true; 49 | } 50 | 51 | 52 | #include 53 | 54 | bool foo3() { 55 | const boost::scoped_ptr p(new foo_class("Some initialization data")); 56 | 57 | const bool something_else_happened = some_function1(p.get()); 58 | if (something_else_happened) { 59 | return false; 60 | } 61 | 62 | some_function2(p.get()); 63 | return true; 64 | } 65 | 66 | 67 | #include 68 | 69 | bool foo3_1() { 70 | const boost::movelib::unique_ptr p 71 | = boost::movelib::make_unique("Some initialization data"); 72 | 73 | const bool something_else_happened = some_function1(p.get()); 74 | if (something_else_happened) { 75 | return false; 76 | } 77 | some_function2(p.get()); 78 | return true; 79 | } 80 | 81 | #include 82 | int main() { 83 | try { foo2(); } catch(...){ assert(false); } 84 | try { foo3(); } catch(...){ assert(false); } 85 | try { foo3_1(); } catch(...){ assert(false); } 86 | 87 | g_exit_on_first_function = false; 88 | try { foo2(); assert(false); } catch(...){} 89 | try { foo3(); assert(false); } catch(...){} 90 | try { foo3_1(); assert(false); } catch(...){} 91 | } 92 | 93 | -------------------------------------------------------------------------------- /Chapter02/02_shared_ptr/02_shared_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter02/02_shared_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | class foo_class { 2 | public: 3 | char data[10000000]; 4 | 5 | explicit foo_class(const char* /*param*/){} 6 | }; 7 | 8 | foo_class* get_data() { 9 | static int i = 0; 10 | ++ i; 11 | if (i % 2) { 12 | return new foo_class("Just some string"); 13 | } else { 14 | return 0; 15 | } 16 | } 17 | 18 | 19 | #include 20 | #include 21 | 22 | void process1(const foo_class* p); 23 | void process2(const foo_class* p); 24 | void process3(const foo_class* p); 25 | 26 | void foo1() { 27 | while (foo_class* p = get_data()) // C way 28 | { 29 | // There will be too many threads soon, see 30 | // recipe 'Parallel execution of different tasks' 31 | // for a good way to avoid uncontrolled growth of threads 32 | 33 | boost::thread(boost::bind(&process1, p)) 34 | .detach(); 35 | boost::thread(boost::bind(&process2, p)) 36 | .detach(); 37 | boost::thread(boost::bind(&process3, p)) 38 | .detach(); 39 | // delete p; Oops!!!! 40 | } 41 | } 42 | 43 | 44 | #include 45 | 46 | void process_sp1(const boost::shared_ptr& p); 47 | void process_sp2(const boost::shared_ptr& p); 48 | void process_sp3(const boost::shared_ptr& p); 49 | 50 | void foo2() { 51 | typedef boost::shared_ptr ptr_t; 52 | ptr_t p; 53 | while (p = ptr_t(get_data())) // C way 54 | { 55 | boost::thread(boost::bind(&process_sp1, p)) 56 | .detach(); 57 | boost::thread(boost::bind(&process_sp2, p)) 58 | .detach(); 59 | boost::thread(boost::bind(&process_sp3, p)) 60 | .detach(); 61 | // no need to anything 62 | } 63 | } 64 | 65 | #include 66 | #include 67 | 68 | void process_str1(boost::shared_ptr p); 69 | void process_str2(const boost::shared_ptr& p); 70 | 71 | void foo3() { 72 | boost::shared_ptr ps = boost::make_shared( 73 | "Guess why make_shared " 74 | "is faster than shared_ptr " 75 | "ps(new std::string('this string'))" 76 | ); 77 | 78 | boost::thread(boost::bind(&process_str1, ps)) 79 | .detach(); 80 | boost::thread(boost::bind(&process_str2, ps)) 81 | .detach(); 82 | } 83 | 84 | #include 85 | int main() { 86 | // foo1(); // Will cause a memory leak 87 | foo2(); 88 | foo3(); 89 | 90 | // Give all the threads a chance to finish 91 | // Note: It is an awfull design, but it is OK 92 | // for example 93 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 94 | return 0; 95 | } 96 | 97 | #include 98 | 99 | 100 | void process1(const foo_class* p) { 101 | assert(p); 102 | } 103 | 104 | void process2(const foo_class* p) { 105 | assert(p); 106 | } 107 | 108 | void process3(const foo_class* p) { 109 | assert(p); 110 | } 111 | 112 | void process_str1(boost::shared_ptr p) { 113 | assert(p); 114 | } 115 | 116 | void process_str2(const boost::shared_ptr& p) { 117 | assert(p); 118 | } 119 | void process_sp1(const boost::shared_ptr& p) { 120 | assert(!!p); 121 | } 122 | 123 | void process_sp2(const boost::shared_ptr& p) { 124 | assert(!!p); 125 | } 126 | 127 | void process_sp3(const boost::shared_ptr& p) { 128 | assert(!!p); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /Chapter02/03_scoped_array/03_scoped_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/03_scoped_array/main.cpp: -------------------------------------------------------------------------------- 1 | void may_throw1(const char* buffer); 2 | void may_throw2(const char* buffer); 3 | 4 | void foo() { 5 | // we can not allocate 10MB of memory on stack, 6 | // so we allocate it on heap 7 | char* buffer = new char[1024 * 1024 * 10]; 8 | 9 | // Here comes some code, that may throw 10 | may_throw1(buffer); 11 | may_throw2(buffer); 12 | 13 | delete[] buffer; 14 | } 15 | 16 | #include 17 | 18 | void foo_fixed() { 19 | // so we allocate it on heap 20 | boost::scoped_array buffer(new char[1024 * 1024 * 10]); 21 | 22 | // Here comes some code, that may throw, 23 | // but now exception won't couse a memory leak 24 | may_throw1(buffer.get()); 25 | may_throw2(buffer.get()); 26 | 27 | // destructor of 'buffer' variable will call delete[] 28 | } 29 | 30 | #include 31 | #include 32 | 33 | int main() { 34 | // foo(); // Leaks memory 35 | try { 36 | foo_fixed(); 37 | } catch (...){} 38 | 39 | return 0; 40 | } 41 | 42 | 43 | void may_throw1(const char* /*buffer*/) { 44 | // Do nothing 45 | } 46 | 47 | void may_throw2(const char* /*buffer*/) { 48 | throw std::exception(); 49 | } 50 | -------------------------------------------------------------------------------- /Chapter02/04_shared_array/04_shared_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter02/04_shared_array/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void do_process(const char* data, std::size_t size); 6 | 7 | void do_process_in_background(const char* data, std::size_t size) { 8 | // We need to copy data, because we do not know, 9 | // when it will be deallocated by the caller 10 | char* data_cpy = new char[size]; 11 | std::memcpy(data_cpy, data, size); 12 | 13 | // Starting thread of execution to process data 14 | boost::thread(boost::bind(&do_process, data_cpy, size)); 15 | 16 | // We can not delete[] data_cpy, because 17 | // do_process1 or do_process2 may still work with it 18 | } 19 | 20 | #include 21 | void do_process_shared_array(const boost::shared_array& data, std::size_t size) { 22 | do_process(data.get(), size); 23 | } 24 | 25 | void do_process_in_background_v1(const char* data, std::size_t size) { 26 | // We need to copy data, because we do not know, when it will be 27 | // deallocated by the caller 28 | boost::shared_array data_cpy(new char[size]); 29 | std::memcpy(data_cpy.get(), data, size); 30 | 31 | // Starting thread of execution to process data 32 | boost::thread(boost::bind(&do_process_shared_array, data_cpy, size)) 33 | .detach(); 34 | 35 | // no need to call delete[] for data_cpy, because 36 | // data_cpy destructor will deallocate data when 37 | // reference count will be zero 38 | } 39 | 40 | 41 | #include 42 | #include 43 | 44 | void do_process_shared_ptr( 45 | const boost::shared_ptr& data, 46 | std::size_t size) 47 | { 48 | do_process(data.get(), size); 49 | } 50 | 51 | void do_process_in_background_v2(const char* data, std::size_t size) { 52 | // Faster than 'First solution' 53 | boost::shared_ptr data_cpy = boost::make_shared(size); 54 | std::memcpy(data_cpy.get(), data, size); 55 | 56 | // Starting thread of execution to process data 57 | boost::thread(boost::bind(&do_process_shared_ptr, data_cpy, size)) 58 | .detach(); 59 | 60 | // data_cpy destructor will deallocate data when 61 | // reference count will be zero 62 | } 63 | 64 | void do_process_shared_ptr2( 65 | const boost::shared_ptr& data, 66 | std::size_t size) 67 | { 68 | do_process(data.get(), size); 69 | } 70 | 71 | void do_process_in_background_v3(const char* data, std::size_t size) { 72 | // Same speed as in First solution 73 | boost::shared_ptr data_cpy( 74 | new char[size], 75 | boost::checked_array_deleter() 76 | ); 77 | std::memcpy(data_cpy.get(), data, size); 78 | 79 | // Starting threads of execution to process data 80 | boost::thread(boost::bind(&do_process_shared_ptr2, data_cpy, size)) 81 | .detach(); 82 | 83 | // data_cpy destructor will deallocate data when 84 | // reference count will be zero 85 | } 86 | 87 | #include 88 | int main () { 89 | // do_process_in_background(); // Will cause a memory leak 90 | char ch[] = "Hello dear reader."; 91 | do_process_in_background_v1(ch, sizeof(ch)); 92 | do_process_in_background_v2(ch, sizeof(ch)); 93 | do_process_in_background_v3(ch, sizeof(ch)); 94 | 95 | // Give all the threads a chance to finish 96 | // Note: It is an awfull design, but it is OK 97 | // for example 98 | boost::this_thread::sleep_for(boost::chrono::seconds(2)); 99 | return 0; 100 | } 101 | 102 | void do_process(const char* data, std::size_t size) { 103 | assert(size); 104 | assert(data); 105 | } 106 | -------------------------------------------------------------------------------- /Chapter02/05_function_fobject/05_function_fobject.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/05_function_fobject/main.cpp: -------------------------------------------------------------------------------- 1 | // Required for std::unary_function<> template 2 | #include 3 | // making a typedef for function pointer accepting int 4 | // and returning nothing 5 | typedef void (*func_t)(int); 6 | 7 | // Function that accepts pointer to function and 8 | // calls accepted function for each integer that it has 9 | // It can not work with functional objects :( 10 | void process_integers(func_t f); 11 | 12 | // Functional object 13 | class int_processor: public std::unary_function { 14 | const int min_; 15 | const int max_; 16 | bool& triggered_; 17 | 18 | public: 19 | int_processor(int min, int max, bool& triggered) 20 | : min_(min) 21 | , max_(max) 22 | , triggered_(triggered) 23 | {} 24 | 25 | void operator()(int i) const { 26 | if (i < min_ || i > max_) { 27 | triggered_ = true; 28 | } 29 | } 30 | }; 31 | 32 | #include 33 | typedef boost::function fobject_t; 34 | 35 | // Now this function may accept functional objects 36 | void process_integers(const fobject_t& f); 37 | 38 | int main() { 39 | bool is_triggered = false; 40 | int_processor fo(0, 200, is_triggered); 41 | process_integers(fo); 42 | assert(is_triggered); 43 | } 44 | 45 | void foo(const fobject_t& f) { 46 | // boost::function is convertible to bool 47 | if (f) { 48 | // we have value in 'f' 49 | // ... 50 | } else { 51 | // 'f' is empty 52 | // ... 53 | } 54 | } 55 | 56 | bool g_is_triggered = false; 57 | void set_functional_object(fobject_t& f) { 58 | int_processor fo( 100, 200, g_is_triggered); 59 | f = fo; 60 | // fo leaves scope and will be destroyed, 61 | // but 'f' will be usable even in outer scope 62 | } 63 | 64 | #include 65 | #include 66 | #include 67 | void foo1() { 68 | std::vector v; 69 | std::for_each(v.begin(), v.end(), boost::bind(std::plus(), 10, _1)); 70 | 71 | fobject_t f(boost::bind(std::plus(), 10, _1)); 72 | std::for_each(v.begin(), v.end(), f); 73 | } 74 | 75 | void process_integers(const fobject_t& f) { 76 | static const int data[] = {1, 2, 3, 4, 5, 250}; 77 | std::for_each(data, data + sizeof(data) / sizeof(int), f); 78 | } 79 | -------------------------------------------------------------------------------- /Chapter02/06_function_fpointer/06_function_fpointer.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/06_function_fpointer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | typedef boost::function fobject_t; 3 | 4 | // Now this function may accept functional objects 5 | void process_integers(const fobject_t& f); 6 | 7 | 8 | void my_ints_function(int i); 9 | 10 | int main() { 11 | process_integers(&my_ints_function); 12 | } 13 | 14 | void my_ints_function(int /*i*/) {} 15 | void process_integers(const fobject_t& f) { f(10); } 16 | -------------------------------------------------------------------------------- /Chapter02/07_function_lambda_c++11/07_function_lambda_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter02/07_function_lambda_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | typedef boost::function fobject_t; 3 | 4 | // Now this function may accept functional objects 5 | void process_integers(const fobject_t& f); 6 | 7 | #include 8 | #include 9 | int main() { 10 | // lambda function with no parameters that does nothing 11 | process_integers([](int /*i*/){}); 12 | 13 | // lambda function that stores a reference 14 | std::deque ints; 15 | process_integers([&ints](int i){ 16 | ints.push_back(i); 17 | }); 18 | 19 | // lambda function that modifies its content 20 | std::size_t match_count = 0; 21 | process_integers([ints, &match_count](int i) mutable { 22 | if (ints.front() == i) { 23 | ++ match_count; 24 | } 25 | ints.pop_front(); 26 | }); 27 | 28 | assert(match_count == 6); 29 | } 30 | 31 | void process_integers(const fobject_t& f) { 32 | static const int data[] = {1, 2, 3, 4, 5, 200, 0}; 33 | // We'll be using only 6 elements in this example 34 | std::for_each(data, data + 6, f); 35 | } 36 | -------------------------------------------------------------------------------- /Chapter02/08_ptr_container_c++11/08_ptr_container_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter02/08_ptr_container_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | struct ptr_cmp: public std::binary_function { 9 | template 10 | bool operator()(const T1& v1, const T1& v2) const { 11 | return operator ()(*v1, *v2); 12 | } 13 | 14 | bool operator()(const T& v1, const T& v2) const { 15 | return std::less()(v1, v2); 16 | } 17 | }; 18 | 19 | template 20 | struct ptr_deleter: public std::unary_function { 21 | void operator()(T* ptr) { 22 | delete ptr; 23 | } 24 | }; 25 | 26 | void example1() { 27 | 28 | std::set > s; 29 | s.insert(new int(1)); 30 | s.insert(new int(0)); 31 | 32 | // ... 33 | assert(**s.begin() == 0); 34 | 35 | // ... 36 | // Deallocating resources 37 | // Any exception in this code will lead to 38 | // memory leak 39 | std::for_each(s.begin(), s.end(), ptr_deleter()); 40 | } 41 | 42 | //void example2_a() { 43 | // typedef std::auto_ptr int_aptr_t; 44 | // std::set > s; 45 | // s.insert(int_aptr_t(new int(1))); 46 | // s.insert(int_aptr_t(new int(0))); 47 | // // ... 48 | // assert(**s.begin() == 0); 49 | // // ... 50 | // // resources will be deallocated by auto_ptr<> 51 | //} 52 | 53 | void example2_b() { 54 | typedef std::unique_ptr int_uptr_t; 55 | std::set > s; 56 | s.insert(int_uptr_t(new int(1))); 57 | s.insert(int_uptr_t(new int(0))); 58 | // ... 59 | assert(**s.begin() == 0); 60 | // ... 61 | // resources will be deallocated by unique_ptr<> 62 | } 63 | 64 | #include 65 | void example3() { 66 | typedef boost::shared_ptr int_sptr_t; 67 | std::set > s; 68 | s.insert(int_sptr_t(new int(1))); 69 | s.insert(int_sptr_t(new int(0))); 70 | // ... 71 | assert(**s.begin() == 0); 72 | // ... 73 | // resources will be deallocated by shared_ptr<> 74 | } 75 | 76 | #include 77 | void correct_impl() { 78 | boost::ptr_set s; 79 | s.insert(new int(1)); 80 | s.insert(new int(0)); 81 | // ... 82 | assert(*s.begin() == 0); 83 | // ... 84 | // resources will be deallocated by container itself 85 | } 86 | 87 | #include 88 | #include 89 | void theres_more_example() { 90 | // Creating vector of 10 elements with values 100 91 | boost::ptr_vector v; 92 | int value = 100; 93 | v.resize(10, &value); // Beware! No ownership of pointer! 94 | assert(v.size() == 10); 95 | assert(v.back() == 100); 96 | } 97 | 98 | int main() { 99 | example1(); 100 | // example2_a(); 101 | example2_b(); 102 | example3(); 103 | correct_impl(); 104 | theres_more_example(); 105 | } 106 | -------------------------------------------------------------------------------- /Chapter02/09_scope_exit/09_scope_exit.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/09_scope_exit/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::FILE* f = std::fopen("example_file.txt", "w"); 8 | assert(f); 9 | BOOST_SCOPE_EXIT(f) { 10 | // Whatever happened in scope, this code will be executed 11 | // and file will be correctly closed. 12 | std::fclose(f); 13 | } BOOST_SCOPE_EXIT_END 14 | 15 | // Some code that may throw or return. 16 | // ... 17 | } 18 | 19 | class theres_more_example { 20 | public: 21 | void close(std::FILE*); 22 | 23 | void theres_more_example_func() { 24 | std::FILE* f = 0; 25 | BOOST_SCOPE_EXIT(f, this_) { // Capture object `this_`. 26 | this_->close(f); 27 | } BOOST_SCOPE_EXIT_END 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /Chapter02/10_base_from_member/10_base_from_member.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/10_base_from_member/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class tasks_processor: boost::noncopyable { 5 | std::ostream& log_; 6 | 7 | protected: 8 | virtual void do_process() = 0; 9 | 10 | public: 11 | explicit tasks_processor(std::ostream& log) 12 | : log_(log) 13 | {} 14 | 15 | void process() { 16 | log_ << "Starting data processing"; 17 | do_process(); 18 | } 19 | }; 20 | 21 | class fake_tasks_processor: public tasks_processor { 22 | std::ostringstream logger_; 23 | 24 | virtual void do_process() { 25 | logger_ << "Fake processor processed!"; 26 | } 27 | 28 | public: 29 | fake_tasks_processor() 30 | : tasks_processor(logger_) // Oops! logger_ does not exist here 31 | , logger_() 32 | {} 33 | 34 | #ifdef NEWER_DEFINED1 35 | fake_tasks_processor() 36 | : logger_() // Oops! logger_ still will be constructed AFTER tasks_processor 37 | , tasks_processor(logger_) 38 | {} 39 | #endif 40 | 41 | }; 42 | 43 | #include 44 | class fake_tasks_processor_fixed 45 | : boost::base_from_member 46 | , public tasks_processor 47 | { 48 | typedef boost::base_from_member logger_t; 49 | 50 | virtual void do_process() { 51 | logger_t::member << "Fake processor processed!"; 52 | } 53 | 54 | public: 55 | fake_tasks_processor_fixed() 56 | : logger_t() 57 | , tasks_processor(logger_t::member) 58 | {} 59 | }; 60 | 61 | class fake_tasks_processor2 62 | : boost::base_from_member 63 | , boost::base_from_member 64 | , public tasks_processor 65 | { 66 | 67 | typedef boost::base_from_member logger0_t; 68 | typedef boost::base_from_member logger1_t; 69 | 70 | virtual void do_process() { 71 | logger0_t::member << "0: Fake processor2 processed!"; 72 | logger1_t::member << "1: Fake processor2 processed!"; 73 | } 74 | 75 | public: 76 | fake_tasks_processor2() 77 | : logger0_t() 78 | , logger1_t() 79 | , tasks_processor(logger0_t::member) 80 | {} 81 | }; 82 | 83 | 84 | int main() { 85 | fake_tasks_processor_fixed tp; 86 | tp.process(); 87 | 88 | fake_tasks_processor2 tp2; 89 | tp2.process(); 90 | } 91 | -------------------------------------------------------------------------------- /Chapter02/Chapter02.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_scoped_ptr \ 5 | 02_shared_ptr \ 6 | 03_scoped_array \ 7 | 04_shared_array \ 8 | 05_function_fobject \ 9 | 06_function_fpointer \ 10 | 07_function_lambda_c++11 \ 11 | 08_ptr_container_c++11 \ 12 | 09_scope_exit \ 13 | 10_base_from_member 14 | -------------------------------------------------------------------------------- /Chapter03/01_lexical_to_number/01_lexical_to_number.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter03/01_lexical_to_number/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void foo1() { 4 | std::istringstream iss("100"); 5 | int i; 6 | iss >> i; 7 | // And now, 'iss' variable will get in the way all the time, till end of the scope 8 | // It is better not to think, how many unnecessary operations, virtual function calls and memory allocations occurred during those operations 9 | } 10 | 11 | #include 12 | void foo2() { 13 | char * end; 14 | int i = std::strtol ("100", &end, 10); 15 | // Did it converted all the value to int, or stopped somewere in the middle? 16 | // And now we have 'end' variable will geting in the way 17 | // By the way, we wante an integer, but strtol returns long int... Did the converted value fit in int? 18 | 19 | (void)i; // Supressing warning about unused variable 20 | } 21 | 22 | #include 23 | 24 | void foo3() { 25 | { 26 | int i = boost::lexical_cast("100"); 27 | (void)i; // Supressing warning about unused variable 28 | } 29 | 30 | char chars[] = {'1', '0', '0' }; 31 | int i = boost::lexical_cast(chars, 3); 32 | assert(i == 100); 33 | 34 | 35 | 36 | try { 37 | // on x86 short usually may not store values greater than 32767 38 | short s = boost::lexical_cast("1000000"); 39 | assert(false); // Must not reach this 40 | (void)s; // Supressing warning about unused variable 41 | } catch (const boost::bad_lexical_cast& /*e*/) {} 42 | 43 | 44 | try { 45 | int i = boost::lexical_cast("This is not a number!"); 46 | assert(false); // Must not reach this 47 | (void)i; // Supressing warning about unused variable 48 | } catch (const boost::bad_lexical_cast& /*e*/) {} 49 | } 50 | 51 | #include 52 | void foo4() { 53 | std::locale::global(std::locale("ru_RU.UTF8")); 54 | // In Russia coma sign is used as a decimal separator 55 | float f = boost::lexical_cast("1,0"); 56 | assert(f < 1.01 && f > 0.99); 57 | std::locale::global(std::locale::classic()); // Restoring C locale 58 | } 59 | 60 | 61 | 62 | #include 63 | #include 64 | #include 65 | #include 66 | 67 | template 68 | std::vector container_to_longs(const ContainerT& container) { 69 | typedef typename ContainerT::value_type value_type; 70 | std::vector ret; 71 | typedef long int (*func_t)(const value_type&); 72 | func_t f = &boost::lexical_cast; 73 | std::transform(container.begin(), container.end(), std::back_inserter(ret), f); 74 | return ret; 75 | } 76 | 77 | #include 78 | #include 79 | #include 80 | #include 81 | 82 | void foo5() { 83 | // Somewhere in source file... 84 | std::set str_set; 85 | str_set.insert("1"); 86 | assert(container_to_longs(str_set).front() == 1); 87 | 88 | std::deque char_deque; 89 | char_deque.push_front("1"); 90 | char_deque.push_back("2"); 91 | assert(container_to_longs(char_deque).front() == 1); 92 | assert(container_to_longs(char_deque).back() == 2); 93 | 94 | // Obfuscating people with curly braces is fun! 95 | typedef boost::array element_t; 96 | boost::array arrays = {{ {{'1', '0'}}, {{'2', '0'}} }}; 97 | assert(container_to_longs(arrays).front() == 10); 98 | assert(container_to_longs(arrays).back() == 20); 99 | } 100 | 101 | 102 | int main() { 103 | foo1(); 104 | foo2(); 105 | foo3(); 106 | foo4(); 107 | foo5(); 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /Chapter03/02_lexical_to_string/02_lexical_to_string.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/02_lexical_to_string/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void foo1() { 5 | std::string s = boost::lexical_cast(100); 6 | assert(s == "100"); 7 | } 8 | 9 | #include 10 | void foo2() { 11 | // C++ way of converting to strings 12 | std::stringstream ss; 13 | ss << 100; 14 | std::string s; 15 | ss >> s; 16 | // Variable 'ss' will dangle all the way, till the end of scope 17 | // Multiple virtual methods were called during conversion 18 | assert(s == "100"); 19 | } 20 | 21 | #include 22 | void foo3() { 23 | // C way of converting to strings 24 | char buffer[100]; 25 | std::sprintf(buffer, "%i", 100); 26 | // You will need an unsigned long long int type to count how many 27 | // times errors were made in 'printf' like functions all around the 28 | // world. 'printf' functions are a constant security threat! 29 | // But wait, we still need to construct a std::string 30 | std::string s(buffer); 31 | // And now we have an buffer variable that won't be used 32 | assert(s == "100"); 33 | } 34 | 35 | 36 | int main() { 37 | foo1(); 38 | foo2(); 39 | foo3(); 40 | } 41 | -------------------------------------------------------------------------------- /Chapter03/03_numeric_cast/03_numeric_cast.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/04_lexical_user_defined/04_lexical_user_defined.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/04_lexical_user_defined/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Negative number, that does not stores minus sign 5 | class negative_number { 6 | unsigned short number_; 7 | 8 | public: 9 | explicit negative_number(unsigned short number = 0) 10 | : number_(number) 11 | {} 12 | 13 | // operators and functions defined lower 14 | // ... 15 | unsigned short value_without_sign() const { 16 | return number_; 17 | } 18 | }; 19 | 20 | std::ostream& operator<<(std::ostream& os, const negative_number& num) { 21 | os << '-' << num.value_without_sign(); 22 | return os; 23 | } 24 | 25 | std::istream& operator>>(std::istream& is, negative_number& num) { 26 | char ch; 27 | is >> ch; 28 | if (ch != '-') { 29 | throw std::logic_error("negative_number class designed to store ONLY negative values"); 30 | } 31 | 32 | unsigned short s; 33 | is >> s; 34 | num = negative_number(s); 35 | return is; 36 | } 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | void foo1() { 44 | negative_number n = boost::lexical_cast("-100"); 45 | assert(n.value_without_sign() == 100); 46 | 47 | 48 | int i = boost::lexical_cast(n); 49 | assert(i == -100); 50 | 51 | typedef boost::array arr_t; 52 | arr_t arr = boost::lexical_cast(n); 53 | assert(arr[0] == '-'); 54 | assert(arr[1] == '1'); 55 | assert(arr[2] == '0'); 56 | assert(arr[3] == '0'); 57 | assert(arr[4] == '\0'); 58 | } 59 | 60 | 61 | template 62 | std::basic_ostream& operator<<(std::basic_ostream& os, const negative_number& num) { 63 | os << static_cast('-') << num.value_without_sign(); 64 | return os; 65 | } 66 | 67 | template 68 | std::basic_istream& operator>>(std::basic_istream& is, negative_number& num) { 69 | CharT ch; 70 | is >> ch; 71 | if (ch != static_cast('-')) { 72 | throw std::logic_error("negative_number class designed to store ONLY negative values"); 73 | } 74 | 75 | unsigned short s; 76 | is >> s; 77 | num = negative_number(s); 78 | return is; 79 | } 80 | 81 | void foo2() { 82 | negative_number n = boost::lexical_cast(L"-1"); 83 | assert(n.value_without_sign() == 1); 84 | 85 | typedef boost::array warr_t; 86 | warr_t arr = boost::lexical_cast(n); 87 | assert(arr[0] == L'-'); 88 | assert(arr[1] == L'1'); 89 | assert(arr[2] == L'\0'); 90 | } 91 | 92 | 93 | int main() { 94 | foo1(); 95 | foo2(); 96 | } 97 | -------------------------------------------------------------------------------- /Chapter03/05_polymorphic_cast/05_polymorphic_cast.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/05_polymorphic_cast/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct object { 4 | virtual ~object() {} 5 | }; 6 | 7 | struct banana: public object { 8 | void eat() const {} 9 | virtual ~banana(){} 10 | }; 11 | 12 | struct pidgin: public object { 13 | void fly() const {} 14 | virtual ~pidgin(){} 15 | }; 16 | 17 | object* try_produce_banana(); 18 | 19 | void try_eat_banana_impl1() { 20 | const object* obj = try_produce_banana(); 21 | if (!obj) { 22 | throw std::bad_cast(); 23 | } 24 | 25 | dynamic_cast(*obj).eat(); 26 | } 27 | 28 | void try_eat_banana_impl2() { 29 | const object* obj = try_produce_banana(); 30 | boost::polymorphic_cast(obj)->eat(); 31 | } 32 | 33 | 34 | 35 | object* try_produce_banana() { 36 | static pidgin pidg; 37 | static banana banan; 38 | static int i = 0; 39 | ++ i; 40 | if (i == 3 || i == 6) { 41 | return 0; 42 | } else if (i == 2 || i == 5) { 43 | return &pidg; 44 | } 45 | return &banan; 46 | } 47 | 48 | #include 49 | using namespace std; 50 | 51 | int main() 52 | { 53 | 54 | try_eat_banana_impl1(); 55 | 56 | try { 57 | try_eat_banana_impl1(); 58 | assert(false); 59 | } catch(...){} 60 | 61 | try { 62 | try_eat_banana_impl1(); 63 | assert(false); 64 | } catch(...){} 65 | 66 | try_eat_banana_impl2(); 67 | try { 68 | try_eat_banana_impl2(); 69 | assert(false); 70 | } catch(...){} 71 | 72 | try { 73 | try_eat_banana_impl2(); 74 | assert(false); 75 | } catch(...){} 76 | return 0; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Chapter03/06_spirit/06_spirit.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/06_spirit/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct date { 7 | unsigned short year; 8 | unsigned short month; 9 | unsigned short day; 10 | }; 11 | 12 | // See recipe "Type 'reference to string'" for a better type 13 | // than std::string for parameter 's' 14 | date parse_date_time1(const std::string& s) { 15 | using boost::spirit::qi::_1; 16 | using boost::spirit::qi::ushort_; 17 | using boost::spirit::qi::char_; 18 | using boost::phoenix::ref; 19 | 20 | date res; 21 | const char* first = s.data(); 22 | const char* const end = first + s.size(); 23 | bool success = boost::spirit::qi::parse(first, end, 24 | ushort_[ ref(res.year) = _1 ] >> char_('-') >> ushort_[ ref(res.month) = _1 ] >> char_('-') >> ushort_[ ref(res.day) = _1 ] 25 | ); 26 | 27 | if (!success || first != end) { 28 | throw std::logic_error("Parsing failed"); 29 | } 30 | 31 | return res; 32 | } 33 | 34 | date parse_date_time2(const std::string& s) { 35 | using boost::spirit::qi::_1; 36 | using boost::spirit::qi::uint_parser; 37 | using boost::spirit::qi::char_; 38 | using boost::phoenix::ref; 39 | 40 | // Use unsigned short as output type, require Radix 10, and from 2 to 2 digits 41 | uint_parser u2_; 42 | 43 | // Use unsigned short as output type, require Radix 10, and from 4 to 4 digits 44 | uint_parser u4_; 45 | 46 | date res; 47 | const char* first = s.data(); 48 | const char* const end = first + s.size(); 49 | bool success = boost::spirit::qi::parse(first, end, 50 | u4_ [ ref(res.year) = _1 ] >> char_('-') >> u2_ [ ref(res.month) = _1 ] >> char_('-') >> u2_ [ ref(res.day) = _1 ] 51 | ); 52 | 53 | if (!success || first != end) { 54 | throw std::logic_error("Parsing failed"); 55 | } 56 | 57 | return res; 58 | } 59 | 60 | 61 | int main() { 62 | date d = parse_date_time1("2012-12-31"); 63 | assert(d.year == 2012); 64 | assert(d.month == 12); 65 | assert(d.day == 31); 66 | 67 | parse_date_time2("2012-12-31"); 68 | assert(d.year == 2012); 69 | assert(d.month == 12); 70 | assert(d.day == 31); 71 | 72 | try { 73 | parse_date_time2("12345-12-31"); 74 | assert(false); 75 | }catch (const std::logic_error&) {} 76 | } 77 | 78 | // ushort_[ [&res](unsigned short s) {res.year = s;} ] >> char_('-') >> ushort_[ ref(res.month) = _1 ] >> char_('-') >> ushort_[ ref(res.day) = _1 ] 79 | -------------------------------------------------------------------------------- /Chapter03/07_spirit_rules/07_spirit_rules.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/Chapter03.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_lexical_to_number \ 5 | 02_lexical_to_string \ 6 | 03_numeric_cast \ 7 | 04_lexical_user_defined \ 8 | 05_polymorphic_cast \ 9 | 06_spirit \ 10 | 07_spirit_rules 11 | -------------------------------------------------------------------------------- /Chapter04/Chapter04.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | static_assert \ 5 | enable_if_c \ 6 | disable_if_c \ 7 | mpl_int_ \ 8 | is_stdvector \ 9 | conditional \ 10 | typeof 11 | 12 | -------------------------------------------------------------------------------- /Chapter04/conditional/conditional.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/conditional/main.cpp: -------------------------------------------------------------------------------- 1 | namespace detail { 2 | struct pre_inc_functor { 3 | template 4 | void operator()(T& value) const { 5 | ++ value; 6 | } 7 | }; 8 | 9 | struct post_inc_functor { 10 | template 11 | void operator()(T& value) const { 12 | value++; 13 | } 14 | }; 15 | 16 | struct plus_assignable_functor { 17 | template 18 | void operator()(T& value) const { 19 | value += T(1); 20 | } 21 | }; 22 | 23 | struct plus_functor { 24 | template 25 | void operator()(T& value) const { 26 | value = value + T(1); 27 | } 28 | }; 29 | } 30 | 31 | 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | template 40 | void inc(T& value) { 41 | // call ++value 42 | // or call value ++ 43 | // or value += T(1); 44 | // or value = value + T(1); 45 | 46 | typedef detail::plus_functor step_0_t; 47 | 48 | typedef typename boost::conditional< 49 | boost::has_plus_assign::value, 50 | detail::plus_assignable_functor, 51 | step_0_t 52 | >::type step_1_t; 53 | 54 | typedef typename boost::conditional< 55 | boost::has_post_increment::value, 56 | detail::post_inc_functor, 57 | step_1_t 58 | >::type step_2_t; 59 | 60 | typedef typename boost::conditional< 61 | boost::has_pre_increment::value, 62 | detail::pre_inc_functor, 63 | step_2_t 64 | >::type step_3_t; 65 | 66 | step_3_t() // default constructing functor 67 | (value); // calling operator() of a functor 68 | } 69 | 70 | struct has_only_postinc { 71 | has_only_postinc operator ++(int) { 72 | return *this; 73 | } 74 | }; 75 | 76 | struct has_only_plus { 77 | explicit has_only_plus(int){} 78 | }; 79 | 80 | has_only_plus operator + (has_only_plus v1, has_only_plus ) { 81 | return v1; 82 | } 83 | 84 | #include 85 | template 86 | void inc_mpl(T& value) { 87 | typedef detail::plus_functor step_0_t; 88 | 89 | typedef typename boost::mpl::if_< 90 | boost::has_plus_assign, 91 | detail::plus_assignable_functor, 92 | step_0_t 93 | >::type step_1_t; 94 | 95 | typedef typename boost::mpl::if_< 96 | boost::has_post_increment, 97 | detail::post_inc_functor, 98 | step_1_t 99 | >::type step_2_t; 100 | 101 | typedef typename boost::mpl::if_< 102 | boost::has_pre_increment, 103 | detail::pre_inc_functor, 104 | step_2_t 105 | >::type step_3_t; 106 | 107 | step_3_t() // default constructing functor 108 | (value); // calling operator() of a functor 109 | } 110 | 111 | #include 112 | int main() { 113 | int i = 0; 114 | inc(i); 115 | assert(i == 1); 116 | 117 | has_only_postinc pi; 118 | inc(pi); 119 | 120 | has_only_plus v(0); 121 | inc(v); 122 | 123 | inc_mpl(i); 124 | assert(i == 2); 125 | inc_mpl(pi); 126 | inc_mpl(v); 127 | } 128 | -------------------------------------------------------------------------------- /Chapter04/disable_if_c/disable_if_c.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter04/disable_if_c/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //template 5 | //T process_data(const T& v1, const T& v2, const T& v3); 6 | 7 | template 8 | T process_data_plus_assign(const T& v1, const T& v2, const T& v3){ 9 | BOOST_STATIC_ASSERT((boost::is_same::value)); 10 | (void)v2; 11 | (void)v3; 12 | return v1; 13 | } 14 | 15 | #include 16 | #include 17 | 18 | // Modified generic version of process_data 19 | template 20 | typename boost::disable_if_c::value,T>::type 21 | process_data(const T& v1, const T& v2, const T& v3) 22 | { 23 | BOOST_STATIC_ASSERT((boost::is_same::value)); 24 | (void)v2; 25 | (void)v3; 26 | return v1; 27 | } 28 | 29 | // This process_data will call a process_data_plus_assign 30 | template 31 | typename boost::enable_if_c::value, T>::type 32 | process_data(const T& v1, const T& v2, const T& v3) 33 | { 34 | return process_data_plus_assign(v1, v2, v3); 35 | } 36 | 37 | // First version 38 | template 39 | typename boost::disable_if, T>::type 40 | process_data2(const T& v1, const T& v2, const T& v3); 41 | 42 | // process_data_plus_assign 43 | template 44 | typename boost::enable_if, T>::type 45 | process_data2(const T& v1, const T& v2, const T& v3); 46 | 47 | 48 | int main() { 49 | int i = 1; 50 | // Optimized version 51 | process_data(i, i, i); 52 | 53 | // Default version 54 | // Explicitly specifing template parameter 55 | process_data("Testing", "example", "function"); 56 | } 57 | -------------------------------------------------------------------------------- /Chapter04/enable_if_c/enable_if_c.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter04/enable_if_c/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | //// Generic implementation 3 | //template 4 | //class data_processor { 5 | // double process(const T& v1, const T& v2, const T& v3); 6 | //}; 7 | 8 | //// Integral types optimized version 9 | //template 10 | //class data_processor { 11 | // typedef int fast_int_t; 12 | // double process(fast_int_t v1, fast_int_t v2, fast_int_t v3); 13 | //}; 14 | 15 | //// SSE optimized version for float types 16 | //template 17 | //class data_processor { 18 | // double process(double v1, double v2, double v3); 19 | //}; 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | // Generic implementation 29 | template 30 | class data_processor { 31 | // ... 32 | public: 33 | double process(const T& /*v1*/, const T& /*v2*/, const T& /*v3*/) { 34 | BOOST_STATIC_ASSERT((boost::is_same::value)); 35 | return 0.0; 36 | } 37 | }; 38 | 39 | 40 | // Integral types optimized version 41 | template 42 | class data_processor::value >::type> { 43 | // ... 44 | public: 45 | typedef int fast_int_t; 46 | double process(fast_int_t /*v1*/, fast_int_t /*v2*/, fast_int_t /*v3*/){ 47 | BOOST_STATIC_ASSERT((boost::is_same::value || boost::is_same::value)); 48 | return 0.0; 49 | } 50 | }; 51 | 52 | // SSE optimized version for float types 53 | template 54 | class data_processor::value >::type> { 55 | // ... 56 | public: 57 | double process(double /*v1*/, double /*v2*/, double /*v3*/){ 58 | BOOST_STATIC_ASSERT((boost::is_same::value || boost::is_same::value)); 59 | return 0.0; 60 | } 61 | }; 62 | 63 | template 64 | double example_func(T v1, T v2, T v3) { 65 | data_processor proc; 66 | return proc.process(v1, v2, v3); 67 | } 68 | 69 | int main () { 70 | // Integral types optimized version 71 | // will be called 72 | example_func(1, 2, 3); 73 | short s = 0; 74 | example_func(s, s, s); 75 | 76 | // Real types version will be called 77 | example_func(1.0, 2.0, 3.0); 78 | example_func(1.0f, 2.0f, 3.0f); 79 | 80 | // Generic version will be called 81 | example_func("Hello", "word", "processing"); 82 | } 83 | -------------------------------------------------------------------------------- /Chapter04/is_stdvector/is_stdvector.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/is_stdvector/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct is_stdvector: boost::false_type {}; 6 | 7 | template 8 | struct is_stdvector >: boost::true_type {}; 9 | 10 | 11 | #include 12 | int main () { 13 | BOOST_STATIC_ASSERT(is_stdvector >::value); 14 | BOOST_STATIC_ASSERT(!is_stdvector::value); 15 | BOOST_STATIC_ASSERT(!is_stdvector::value); 16 | } 17 | -------------------------------------------------------------------------------- /Chapter04/mpl_int_/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //// Generic implementation 5 | //template 6 | //T process(const T& val) { 7 | // BOOST_STATIC_ASSERT((boost::is_pod::value)); 8 | // // ... 9 | // (void)val; 10 | //} 11 | 12 | #include 13 | 14 | namespace detail { 15 | // Generic implementation 16 | template 17 | T process_impl(const T& val, Tag /*ignore*/) { 18 | // ... 19 | BOOST_STATIC_ASSERT(sizeof(val) != 1 20 | && sizeof(val) != 4 21 | && sizeof(val) != 8 22 | ); 23 | return val; 24 | } 25 | 26 | // 1 byte optimized implementation 27 | template 28 | T process_impl(const T& val, boost::mpl::int_<1> /*ignore*/) { 29 | // ... 30 | BOOST_STATIC_ASSERT(sizeof(val) == 1); 31 | return val; 32 | } 33 | 34 | 35 | // 4 bytes optimized implementation 36 | template 37 | T process_impl(const T& val, boost::mpl::int_<4> /*ignore*/) { 38 | // ... 39 | BOOST_STATIC_ASSERT(sizeof(val) == 4); 40 | return val; 41 | } 42 | 43 | // 8 bytes optimized implementation 44 | template 45 | T process_impl(const T& val, boost::mpl::int_<8> /*ignore*/) { 46 | // ... 47 | BOOST_STATIC_ASSERT(sizeof(val) == 8); 48 | return val; 49 | } 50 | } // namespace detail 51 | 52 | 53 | // will be only dispatching calls 54 | template 55 | T process(const T& val) { 56 | BOOST_STATIC_ASSERT((boost::is_pod::value)); 57 | return detail::process_impl(val, boost::mpl::int_()); 58 | } 59 | 60 | template 61 | struct int_ { 62 | static const int value = Value; 63 | typedef int_ type; 64 | typedef int value_type; 65 | }; 66 | 67 | #include 68 | int main() { 69 | std::cout 70 | << ' ' << process(int(0)) 71 | << ' ' << process(double(1)) 72 | << ' ' << process(float(2)) 73 | << ' ' << process(char(3)) 74 | << ' ' << process(unsigned(4)) 75 | << ' ' << process(short(5)) 76 | << std::endl; 77 | } 78 | -------------------------------------------------------------------------------- /Chapter04/mpl_int_/mpl_int_.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/static_assert/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void serialize_bad(const T& value, boost::array& buffer) { 6 | assert(BufSizeV >= sizeof(value)); 7 | // TODO: fixme 8 | std::memcpy(&buffer[0], &value, sizeof(value)); 9 | } 10 | 11 | #include 12 | #include 13 | 14 | template 15 | void serialize(const T& value, boost::array& buffer) { 16 | BOOST_STATIC_ASSERT(BufSizeV >= sizeof(value)); 17 | BOOST_STATIC_ASSERT(boost::is_pod::value); 18 | 19 | std::memcpy(&buffer[0], &value, sizeof(value)); 20 | } 21 | 22 | BOOST_STATIC_ASSERT(3 >= 1); 23 | 24 | struct some_struct { enum enum_t { value = 1}; }; 25 | BOOST_STATIC_ASSERT(some_struct::value); 26 | 27 | template 28 | struct some_templated_struct { 29 | enum enum_t { value = (sizeof(T1) == sizeof(T2))}; 30 | }; 31 | BOOST_STATIC_ASSERT((some_templated_struct::value)); 32 | 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | template 40 | void type_traits_examples(T1& /*v1*/, T2& /*v2*/) { 41 | // Returns true if T1 is an unsigned number 42 | std::cout << boost::is_unsigned::value; 43 | 44 | // Returns true if T1 has exactly the same type, as T2 45 | std::cout << boost::is_same::value; 46 | 47 | // This line removes const modifier from type of T1. 48 | // Here is what will happen with T1 type if T1 is: 49 | // const int => int 50 | // int => int 51 | // int const volatile => int volatile 52 | // const int& => const int& 53 | typedef typename boost::remove_const::type t1_nonconst_t; 54 | } 55 | 56 | template 57 | void serialize2(const T& value, boost::array& buf) { 58 | BOOST_STATIC_ASSERT_MSG(boost::is_pod::value, 59 | "This serialize2 function may be used only " 60 | "with POD types." 61 | ); 62 | 63 | BOOST_STATIC_ASSERT_MSG(BufSizeV >= sizeof(value), 64 | "Can not fit value to buffer. " 65 | "Make buffer bigger." 66 | ); 67 | 68 | std::memcpy(&buf[0], &value, sizeof(value)); 69 | } 70 | 71 | int main() { 72 | const int i = 1; 73 | type_traits_examples(i, i); 74 | 75 | // Somewhere in code: 76 | boost::array buf; 77 | //serialize2(std::string("Hello word"), buf); 78 | 79 | (void)buf; 80 | } 81 | -------------------------------------------------------------------------------- /Chapter04/static_assert/static_assert.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/typeof/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | BOOST_AUTO(var, boost::bind(std::plus(), _1, _1)); 6 | 7 | //typedef decltype(0.5 + 0.5f) type; 8 | typedef BOOST_TYPEOF(0.5 + 0.5f) type; 9 | 10 | 11 | //template 12 | //auto add(const T1& t1, const T2& t2) ->decltype(t1 + t2) { 13 | // return t1 + t2; 14 | //}; 15 | 16 | template 17 | BOOST_TYPEOF_TPL(T1() + T2()) add(const T1& t1, const T2& t2) { 18 | return t1 + t2; 19 | }; 20 | 21 | 22 | #include 23 | #include 24 | BOOST_STATIC_ASSERT((boost::is_same::value)); 25 | 26 | 27 | namespace readers_project { 28 | template 29 | struct readers_template_class{}; 30 | } 31 | 32 | #include 33 | 34 | typedef 35 | readers_project::readers_template_class 36 | readers_template_class_1; 37 | 38 | typedef BOOST_TYPEOF(boost::get<0>( 39 | boost::make_tuple(readers_template_class_1(), 1) 40 | )) readers_template_class_deduced; 41 | 42 | BOOST_STATIC_ASSERT(( 43 | boost::is_same< 44 | readers_template_class_1, 45 | readers_template_class_deduced 46 | >::value 47 | )); 48 | 49 | BOOST_TYPEOF_REGISTER_TEMPLATE( 50 | readers_project::readers_template_class /*class name*/, 51 | 3 /*number of template classes*/ 52 | ) 53 | 54 | int main () { 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Chapter04/typeof/typeof.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter05/Chapter05.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | thread \ 5 | mutex \ 6 | atomics \ 7 | work_queue \ 8 | shared_lock \ 9 | thread_specific_ptr \ 10 | interruptions \ 11 | thread_group 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter05/atomics/atomics.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/atomics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | boost::atomic shared_i(0); 8 | 9 | void do_inc() { 10 | for (std::size_t i = 0; i < 30000; ++i) { 11 | // do some work 12 | // ... 13 | const int i_snapshot = ++ shared_i; 14 | 15 | // do some work with i_snapshot 16 | // ... 17 | (void) i_snapshot; 18 | } 19 | } 20 | 21 | void do_dec() { 22 | for (std::size_t i = 0; i < 30000; ++i) { 23 | // do some work 24 | // ... 25 | const int i_snapshot = -- shared_i; 26 | 27 | // do some work with i_snapshot 28 | // ... 29 | (void) i_snapshot; 30 | } 31 | } 32 | 33 | 34 | int main() { 35 | boost::thread t1(&do_inc); 36 | boost::thread t2(&do_dec); 37 | 38 | t1.join(); 39 | t2.join(); 40 | 41 | assert(shared_i == 0); 42 | std::cout << "shared_i == " << shared_i << std::endl; 43 | 44 | assert(shared_i.is_lock_free()); 45 | } 46 | 47 | #include 48 | BOOST_STATIC_ASSERT(BOOST_ATOMIC_INT_LOCK_FREE == 2); 49 | -------------------------------------------------------------------------------- /Chapter05/interruptions/interruptions.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/interruptions/main.cpp: -------------------------------------------------------------------------------- 1 | bool stop_parsing = true; 2 | bool not_end_of_parsing = true; 3 | 4 | #include 5 | 6 | void do_parse(); 7 | 8 | int main() { 9 | boost::thread parser_thread(&do_parse); 10 | 11 | // Some code goes here 12 | // ... 13 | 14 | if (stop_parsing) { 15 | // no more parsing required 16 | // TODO: stop parser 17 | } 18 | 19 | if (stop_parsing) { 20 | // no more parsing required 21 | parser_thread.interrupt(); 22 | } 23 | 24 | parser_thread.join(); 25 | } 26 | 27 | void do_parse() { 28 | while (not_end_of_parsing) { 29 | boost::this_thread::interruption_point(); 30 | // Some parsing goes here 31 | 32 | } 33 | 34 | // Newer shall reach this code 35 | assert(false); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Chapter05/mutex/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // In previous recipe we included 5 | // , which includes all 6 | // the classes of Boost.Thread 7 | #include 8 | 9 | namespace without_sync { 10 | 11 | int shared_i = 0; 12 | 13 | void do_inc() { 14 | for (std::size_t i = 0; i < 30000; ++i) { 15 | // do some work 16 | // ... 17 | int i_snapshot = ++ shared_i; 18 | 19 | // do some work with i_snapshot 20 | // ... 21 | (void) i_snapshot; 22 | } 23 | } 24 | 25 | void do_dec() { 26 | for (std::size_t i = 0; i < 30000; ++i) { 27 | // do some work 28 | // ... 29 | int i_snapshot = -- shared_i; 30 | 31 | // do some work with i_snapshot 32 | // ... 33 | (void) i_snapshot; 34 | } 35 | } 36 | 37 | void run() { 38 | boost::thread t1(&do_inc); 39 | boost::thread t2(&do_dec); 40 | 41 | t1.join(); 42 | t2.join(); 43 | 44 | // assert(global_i == 0); // Oops! 45 | std::cout << "shared_i == " << shared_i; 46 | } 47 | 48 | } // namespace without_sync 49 | 50 | #include 51 | #include 52 | 53 | namespace with_sync { 54 | 55 | int shared_i = 0; 56 | boost::mutex i_mutex; 57 | 58 | void do_inc() { 59 | for (std::size_t i = 0; i < 30000; ++i) { 60 | // do some work 61 | // ... 62 | int i_snapshot; 63 | { // Critical section begin 64 | boost::lock_guard lock(i_mutex); 65 | i_snapshot = ++ shared_i; 66 | } // Critical section end 67 | 68 | // do some work with i_snapshot 69 | // ... 70 | (void)i_snapshot; 71 | } 72 | } 73 | 74 | void do_dec() { 75 | for (std::size_t i = 0; i < 30000; ++i) { 76 | // do some work 77 | // ... 78 | int i_snapshot; 79 | { // Critical section begin 80 | boost::lock_guard lock(i_mutex); 81 | i_snapshot = -- shared_i; 82 | } // Critical section end 83 | 84 | // do some work with i_snapshot 85 | // ... 86 | (void) i_snapshot; 87 | } 88 | } 89 | 90 | void run() { 91 | boost::thread t1(&do_inc); 92 | boost::thread t2(&do_dec); 93 | 94 | t1.join(); 95 | t2.join(); 96 | 97 | assert(shared_i == 0); 98 | std::cout << "shared_i == " << shared_i; 99 | } 100 | 101 | } // namespace without_sync 102 | 103 | #include 104 | 105 | int main() { 106 | without_sync::run(); 107 | std::cout << '\n'; 108 | with_sync::run(); 109 | std::cout << '\n'; 110 | } 111 | -------------------------------------------------------------------------------- /Chapter05/mutex/mutex.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/shared_lock/shared_lock.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/thread/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void set_not_first_run(); 6 | bool is_first_run(); 7 | 8 | // Function, that executes for a long time 9 | void fill_file_with_data(char fill_char, std::size_t size, const char* filename) { 10 | std::ofstream ofs(filename); 11 | std::fill_n(std::ostreambuf_iterator(ofs), size, fill_char); 12 | set_not_first_run(); 13 | } 14 | 15 | void example_without_threads() { 16 | // ... 17 | // Somewhere in thread that draws a user interface 18 | if (is_first_run()) { 19 | // This will be executing for a long time during which 20 | // users interface will freeze.. 21 | fill_file_with_data(0, 8 * 1024 * 1024, "save_file.txt"); 22 | } 23 | } 24 | 25 | #include 26 | void example_with_threads() { 27 | // ... 28 | // Somewhere in thread that draws a user interface 29 | if (is_first_run()) { 30 | boost::thread(boost::bind( 31 | &fill_file_with_data, 32 | 0, 33 | 8 * 1024 * 1024, 34 | "save_file.txt" 35 | )).detach(); 36 | } 37 | } 38 | 39 | void example_with_joining_threads() { 40 | // ... 41 | // Somewhere in thread that draws a user interface 42 | if (is_first_run()) { 43 | boost::thread t(boost::bind( 44 | &fill_file_with_data, 45 | 0, 46 | 8 * 1024 * 1024, 47 | "save_file.txt" 48 | )); 49 | 50 | // Do some work 51 | // ... 52 | 53 | // Waiting for thread to finish 54 | t.join(); 55 | } 56 | } 57 | 58 | int main() { 59 | example_with_threads(); 60 | example_with_joining_threads(); 61 | } 62 | 63 | #include 64 | void some_func(); 65 | void example_with_raii() { 66 | boost::scoped_thread t( 67 | (boost::thread(&some_func)) 68 | ); 69 | 70 | // 't' will be joined at scope exit 71 | } 72 | 73 | static bool g_is_first_run = true; 74 | void set_not_first_run() { 75 | g_is_first_run = false; 76 | } 77 | 78 | bool is_first_run() { 79 | return g_is_first_run; 80 | } 81 | 82 | void some_func(){} 83 | -------------------------------------------------------------------------------- /Chapter05/thread/thread.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/thread_group/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | boost::atomic_int g_counter(0); 4 | void some_function(){ ++ g_counter; } 5 | 6 | #include 7 | int main() { 8 | boost::thread t1(&some_function); 9 | boost::thread t2(&some_function); 10 | boost::thread t3(&some_function); 11 | // ... 12 | 13 | t1.join(); 14 | t2.join(); 15 | t3.join(); 16 | 17 | assert(g_counter == 3); 18 | 19 | // Launching 10 threads 20 | boost::thread_group threads; 21 | for (unsigned i = 0; i < 10; ++i) { 22 | threads.create_thread(&some_function); 23 | } 24 | 25 | // Joining all threads 26 | threads.join_all(); 27 | 28 | // We can also interrupt all of them 29 | // by calling threads.interrupt_all(); 30 | 31 | assert(g_counter == 13); 32 | } 33 | -------------------------------------------------------------------------------- /Chapter05/thread_group/thread_group.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/thread_specific_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | class connection: boost::noncopyable { 3 | public: 4 | // Opening a connection is a slow operation 5 | void open(); 6 | 7 | void send_result(int result); 8 | 9 | // Other methods 10 | // ... 11 | int open_count_; 12 | connection(): open_count_(0) {} 13 | }; 14 | 15 | // In header file 16 | #include 17 | connection& get_connection(); 18 | 19 | // In source file 20 | boost::thread_specific_ptr connection_ptr; 21 | 22 | connection& get_connection() { 23 | connection* p = connection_ptr.get(); 24 | if (!p) { 25 | connection_ptr.reset(new connection); 26 | p = connection_ptr.get(); 27 | p->open(); 28 | } 29 | 30 | return *p; 31 | } 32 | 33 | 34 | void task() { 35 | int result = 2; 36 | // Some computations go there 37 | // ... 38 | 39 | // Sending result 40 | get_connection().send_result(result); 41 | } 42 | 43 | void connection::open() { 44 | assert(!open_count_); 45 | open_count_ = 1; 46 | } 47 | 48 | void connection::send_result(int /*result*/) {} 49 | 50 | void run_tasks() { 51 | for (std::size_t i = 0; i < 10000000; ++i) { 52 | task(); 53 | } 54 | } 55 | 56 | #include 57 | 58 | int main() { 59 | boost::thread t1(&run_tasks); 60 | boost::thread t2(&run_tasks); 61 | boost::thread t3(&run_tasks); 62 | boost::thread t4(&run_tasks); 63 | 64 | // Waiting for all the tasks to pop 65 | t1.join(); 66 | t2.join(); 67 | t3.join(); 68 | t4.join(); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Chapter05/thread_specific_ptr/thread_specific_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/work_queue/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | class work_queue { 8 | public: 9 | typedef boost::function task_type; 10 | 11 | private: 12 | std::deque tasks_; 13 | boost::mutex tasks_mutex_; 14 | boost::condition_variable cond_; 15 | 16 | public: 17 | void push_task(const task_type& task) { 18 | boost::unique_lock lock(tasks_mutex_); 19 | tasks_.push_back(task); 20 | lock.unlock(); 21 | 22 | cond_.notify_one(); 23 | } 24 | 25 | task_type try_pop_task() { 26 | task_type ret; 27 | boost::lock_guard lock(tasks_mutex_); 28 | if (!tasks_.empty()) { 29 | ret = tasks_.front(); 30 | tasks_.pop_front(); 31 | } 32 | 33 | return ret; 34 | } 35 | 36 | task_type pop_task() { 37 | boost::unique_lock lock(tasks_mutex_); 38 | while (tasks_.empty()) { 39 | cond_.wait(lock); 40 | } 41 | 42 | task_type ret = tasks_.front(); 43 | tasks_.pop_front(); 44 | 45 | return ret; 46 | } 47 | 48 | void flush() { 49 | // TODO: Seems that there is a small chance 50 | // of loosing the notification because of some 51 | // unknown issue in Boost or libc. 52 | // 53 | // Forcing all the blocked threads to wake up. 54 | boost::lock_guard lock(tasks_mutex_); 55 | cond_.notify_all(); 56 | } 57 | }; 58 | 59 | // Testing 60 | #include 61 | 62 | work_queue g_queue; 63 | 64 | void do_nothing(){} 65 | const std::size_t tests_tasks_count = 3000 /*000*/; 66 | void pusher() { 67 | for (std::size_t i = 0; i < tests_tasks_count; ++i) { 68 | // Adding task to do nothing 69 | g_queue.push_task(&do_nothing); 70 | } 71 | } 72 | 73 | void popper_sync() { 74 | for (std::size_t i = 0; i < tests_tasks_count; ++i) { 75 | g_queue.pop_task() // Getting task 76 | (); // Executing task 77 | } 78 | } 79 | 80 | int main() { 81 | boost::thread pop_sync1(&popper_sync); 82 | boost::thread pop_sync2(&popper_sync); 83 | boost::thread pop_sync3(&popper_sync); 84 | 85 | boost::thread push1(&pusher); 86 | boost::thread push2(&pusher); 87 | boost::thread push3(&pusher); 88 | 89 | // Waiting for all the tasks to push 90 | push1.join(); 91 | push2.join(); 92 | push3.join(); 93 | g_queue.flush(); 94 | 95 | // Waiting for all the tasks to pop 96 | pop_sync1.join(); 97 | pop_sync2.join(); 98 | pop_sync3.join(); 99 | 100 | 101 | // Asserting that no tasks remained, 102 | // and falling though without blocking 103 | assert(!g_queue.try_pop_task()); 104 | 105 | g_queue.push_task(&do_nothing); 106 | // Asserting that there is a task, 107 | // and falling though without blocking 108 | assert(g_queue.try_pop_task()); 109 | 110 | } 111 | -------------------------------------------------------------------------------- /Chapter05/work_queue/work_queue.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter06/Chapter06.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | tasks_processor_base \ 5 | tasks_processor_timers \ 6 | tasks_processor_network \ 7 | tasks_processor_multithread \ 8 | conveyor \ 9 | nonblocking_barrier \ 10 | exception_ptr \ 11 | tasks_processor_signals 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter06/conveyor/conveyor.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter06/exception_ptr/exception_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += ../tasks_processor_base/tasks_processor_base.hpp 6 | SOURCES += main.cpp 7 | LIBS += -lboost_thread -lboost_system 8 | -------------------------------------------------------------------------------- /Chapter06/exception_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../tasks_processor_base/tasks_processor_base.hpp" 2 | using namespace tp_base; 3 | 4 | // Part of tasks_processor class from 5 | // tasks_processor_base.hpp, that must be defined 6 | // Somewhere in source file 7 | tasks_processor& tasks_processor::get() { 8 | static tasks_processor proc; 9 | return proc; 10 | } 11 | 12 | #include 13 | #include 14 | void func_test2(); // Forward declaration 15 | 16 | void process_exception(const boost::exception_ptr& exc) { 17 | try { 18 | boost::rethrow_exception(exc); 19 | } catch (const boost::bad_lexical_cast& /*e*/) { 20 | std::cout << "Lexical cast exception detected\n" << std::endl; 21 | 22 | // Pushing another task to execute 23 | tasks_processor::get().push_task(&func_test2); 24 | } catch (...) { 25 | std::cout << "Can not handle such exceptions:\n" 26 | << boost::current_exception_diagnostic_information() 27 | << std::endl; 28 | 29 | // Stopping 30 | tasks_processor::get().stop(); 31 | } 32 | } 33 | 34 | void func_test1() { 35 | try { 36 | boost::lexical_cast("oops!"); 37 | } catch (...) { 38 | tasks_processor::get().push_task(boost::bind( 39 | &process_exception, boost::current_exception() 40 | )); 41 | } 42 | } 43 | 44 | #include 45 | void func_test2() { 46 | try { 47 | // Some code goes here 48 | BOOST_THROW_EXCEPTION(std::logic_error("Some fatal logic error")); 49 | // Some code goes here 50 | } catch (...) { 51 | tasks_processor::get().push_task(boost::bind( 52 | &process_exception, boost::current_exception() 53 | )); 54 | } 55 | } 56 | 57 | void run_throw(boost::exception_ptr& ptr) { 58 | try { 59 | // A lot of code goes here 60 | } catch (...) { 61 | ptr = boost::current_exception(); 62 | } 63 | } 64 | 65 | int main () { 66 | tasks_processor::get().push_task(&func_test1); 67 | tasks_processor::get().start(); 68 | 69 | 70 | boost::exception_ptr ptr; 71 | // Do some work in parallel 72 | boost::thread t(boost::bind( 73 | &run_throw, 74 | boost::ref(ptr) 75 | )); 76 | 77 | // Some code goes here 78 | // ... 79 | 80 | t.join(); 81 | 82 | // Chacking for exception 83 | if (ptr) { 84 | // Exception occured in thread 85 | boost::rethrow_exception(ptr); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Chapter06/nonblocking_barrier/nonblocking_barrier.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_base/main.cpp: -------------------------------------------------------------------------------- 1 | // Amost all the code for this example is in this header 2 | #include "tasks_processor_base.hpp" 3 | using namespace tp_base; 4 | 5 | // Part of tasks_processor class from 6 | // tasks_processor_base.hpp, that must be defined 7 | // Somewhere in source file 8 | tasks_processor& tasks_processor::get() { 9 | static tasks_processor proc; 10 | return proc; 11 | } 12 | 13 | int g_val = 0; 14 | void func_test() { 15 | ++ g_val; 16 | if (g_val == 3) { 17 | throw std::logic_error("Just checking"); 18 | } 19 | 20 | boost::this_thread::interruption_point(); 21 | if (g_val == 10) { 22 | // Emulation of thread interruption. 23 | // Will be catched and won't stop execution. 24 | throw boost::thread_interrupted(); 25 | } 26 | 27 | if (g_val == 90) { 28 | tasks_processor::get().stop(); 29 | } 30 | } 31 | 32 | int main () { 33 | static const std::size_t tasks_count = 100; 34 | // stop() is called at 90 35 | BOOST_STATIC_ASSERT(tasks_count > 90); 36 | 37 | for (std::size_t i =0; i < tasks_count; ++i) { 38 | tasks_processor::get().push_task(&func_test); 39 | } 40 | 41 | // We can also use result of boost::bind call 42 | // as a task. 43 | tasks_processor::get().push_task( 44 | boost::bind(std::plus(), 2, 2) // counting 2 + 2 45 | ); 46 | 47 | // Processing was not started. 48 | assert(g_val == 0); 49 | 50 | // Will not throw, but blocks till 51 | // one of the tasks it is owning 52 | // calls stop(). 53 | tasks_processor::get().start(); 54 | assert(g_val == 90); 55 | } 56 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_base/tasks_processor_base.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_BASE_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_BASE_HPP 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) 5 | # pragma once 6 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 7 | 8 | #include 9 | #include 10 | 11 | namespace detail { 12 | 13 | template 14 | struct task_wrapped { 15 | private: 16 | T task_unwrapped_; 17 | 18 | public: 19 | explicit task_wrapped(const T& task_unwrapped) 20 | : task_unwrapped_(task_unwrapped) 21 | {} 22 | 23 | void operator()() const { 24 | // resetting interruption 25 | try { 26 | boost::this_thread::interruption_point(); 27 | } catch(const boost::thread_interrupted&){} 28 | 29 | try { 30 | // Executing task 31 | task_unwrapped_(); 32 | } catch (const std::exception& e) { 33 | std::cerr<< "Exception: " << e.what() << '\n'; 34 | } catch (const boost::thread_interrupted&) { 35 | std::cerr<< "Thread interrupted\n"; 36 | } catch (...) { 37 | std::cerr<< "Unknown exception\n"; 38 | } 39 | } 40 | }; 41 | 42 | template 43 | inline task_wrapped make_task_wrapped(const T& task_unwrapped) { 44 | return task_wrapped(task_unwrapped); 45 | } 46 | 47 | } // namespace detail 48 | 49 | 50 | namespace tp_base { 51 | 52 | class tasks_processor: private boost::noncopyable { 53 | protected: 54 | boost::asio::io_service ios_; 55 | boost::asio::io_service::work work_; 56 | 57 | tasks_processor() 58 | : ios_() 59 | , work_(ios_) 60 | {} 61 | 62 | public: 63 | static tasks_processor& get(); 64 | 65 | template 66 | inline void push_task(const T& task_unwrapped) { 67 | ios_.post(detail::make_task_wrapped(task_unwrapped)); 68 | } 69 | 70 | void start() { 71 | ios_.run(); 72 | } 73 | 74 | void stop() { 75 | ios_.stop(); 76 | } 77 | }; // tasks_processor 78 | 79 | } // namespace base:: 80 | 81 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_BASE_HPP 82 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_base/tasks_processor_base.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += tasks_processor_base.hpp 6 | SOURCES += main.cpp 7 | LIBS += -lboost_system -lboost_thread 8 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_multithread/main.cpp: -------------------------------------------------------------------------------- 1 | // See this header some code of this recipe 2 | #include "tasks_processor_multithread.hpp" 3 | using namespace tp_multithread; 4 | 5 | // Part of tasks_processor class from 6 | // tasks_processor_multithread.hpp, that must be defined 7 | // Somewhere in source file 8 | tasks_processor& tasks_processor::get() { 9 | static tasks_processor proc; 10 | return proc; 11 | } 12 | 13 | const std::size_t threads_count = 5; 14 | #include 15 | boost::barrier g_barrier(threads_count); 16 | 17 | void multythread_test() { 18 | g_barrier.wait(); 19 | tasks_processor::get().stop(); 20 | } 21 | 22 | int main() { 23 | for (std::size_t i = 0; i < threads_count; ++i) { 24 | tasks_processor::get().push_task(&multythread_test); 25 | } 26 | time_t t1 = time(NULL); 27 | tasks_processor::get().start_multiple(threads_count); 28 | time_t t2 = time(NULL); 29 | // One additional second for some io_service and OS delays 30 | assert(t2 - t1 < 1); 31 | } 32 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_multithread/tasks_processor_multithread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) 5 | # pragma once 6 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 7 | 8 | #include "../tasks_processor_network/tasks_processor_network.hpp" 9 | 10 | namespace tp_multithread { 11 | 12 | class tasks_processor: public tp_network::tasks_processor { 13 | public: 14 | static tasks_processor& get(); 15 | 16 | // Default value will attempt to guess optimal count of threads 17 | void start_multiple(std::size_t threads_count = 0) { 18 | if (!threads_count) { 19 | threads_count = (std::max)(static_cast( 20 | boost::thread::hardware_concurrency()), 1 21 | ); 22 | } 23 | 24 | // one thread is the current thread 25 | -- threads_count; 26 | 27 | boost::thread_group tg; 28 | for (std::size_t i = 0; i < threads_count; ++i) { 29 | tg.create_thread(boost::bind(&boost::asio::io_service::run, boost::ref(ios_))); 30 | } 31 | 32 | ios_.run(); 33 | tg.join_all(); 34 | } 35 | }; 36 | 37 | } // namespace tp_multithread 38 | 39 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 40 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_multithread/tasks_processor_multithread.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../tasks_processor_base/tasks_processor_base.hpp \ 7 | ../tasks_processor_timers/tasks_processor_timers.hpp \ 8 | ../tasks_processor_network/tasks_processor_network.hpp \ 9 | tasks_processor_multithread.hpp 10 | 11 | 12 | SOURCES += main.cpp 13 | LIBS += -lboost_thread -lboost_system 14 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_network/tasks_processor_network.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../tasks_processor_base/tasks_processor_base.hpp \ 7 | ../tasks_processor_timers/tasks_processor_timers.hpp \ 8 | tasks_processor_network.hpp 9 | 10 | SOURCES += main.cpp 11 | LIBS += -lboost_thread -lboost_system 12 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_signals/main.cpp: -------------------------------------------------------------------------------- 1 | // Almost all the code for this recipe 2 | // is in this header file 3 | #include "tasks_processor_signals.hpp" 4 | using namespace tp_full; 5 | 6 | // Part of tasks_processor class from 7 | // tasks_processor_signals.hpp, that must be defined 8 | // Somewhere in source file 9 | tasks_processor& tasks_processor::get() { 10 | static tasks_processor proc; 11 | return proc; 12 | } 13 | 14 | 15 | void accept_3_signals_and_stop(int signal) { 16 | static int signals_count = 0; 17 | assert(signal == SIGINT); 18 | ++ signals_count; 19 | std::cout << "Captured " << signals_count << " SIGINT\n"; 20 | if (signals_count == 3) { 21 | tasks_processor::get().stop(); 22 | } 23 | } 24 | 25 | 26 | int main () { 27 | tasks_processor::get().register_signals_handler( 28 | &accept_3_signals_and_stop, 29 | std::vector(1, SIGINT) // vector containing 1 element 30 | ); 31 | 32 | tasks_processor::get().start(); 33 | } 34 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_signals/tasks_processor_signals.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) 5 | # pragma once 6 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 7 | 8 | #include "../tasks_processor_multithread/tasks_processor_multithread.hpp" 9 | 10 | 11 | #include 12 | #include 13 | 14 | namespace tp_full { 15 | 16 | class tasks_processor: public tp_multithread::tasks_processor { 17 | /* 18 | tasks_processor() 19 | : ios_() 20 | , work_(ios_) 21 | , signals_(ios_) 22 | {} 23 | */ 24 | 25 | tasks_processor() 26 | : tp_multithread::tasks_processor() 27 | , signals_(ios_) 28 | {} 29 | 30 | 31 | public: 32 | static tasks_processor& get(); 33 | 34 | private: 35 | boost::asio::signal_set signals_; 36 | boost::function users_signal_handler_; 37 | 38 | // private 39 | void handle_signals( 40 | const boost::system::error_code& error, 41 | int signal_number) 42 | { 43 | if (error) { 44 | std::cerr << "Error in signal handling: " << error << '\n'; 45 | } else { 46 | // If signals occures while there is no waiting handlers, 47 | // signal notification is queued, so it won't be missed 48 | // while we running users_signal_handler_ 49 | detail::make_task_wrapped(boost::bind( 50 | boost::ref(users_signal_handler_), signal_number 51 | ))(); // make and run task_wrapped 52 | } 53 | 54 | signals_.async_wait(boost::bind( 55 | &tasks_processor::handle_signals, this, _1, _2 56 | )); 57 | } 58 | public: 59 | 60 | // This function is not threads safe! 61 | // Must be called before all the `start()` calls 62 | // Function can be called only once 63 | template 64 | void register_signals_handler( 65 | const Func& f, 66 | const std::vector& signals_to_wait) 67 | { 68 | // Making shure that this is the first call 69 | assert(!users_signal_handler_); 70 | 71 | users_signal_handler_ = f; 72 | std::for_each( 73 | signals_to_wait.begin(), 74 | signals_to_wait.end(), 75 | boost::bind( 76 | &boost::asio::signal_set::add, &signals_, _1 77 | ) 78 | ); 79 | 80 | signals_.async_wait(boost::bind( 81 | &tasks_processor::handle_signals, this, _1, _2 82 | )); 83 | } 84 | }; 85 | 86 | } // namespace tp_full 87 | 88 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 89 | 90 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_signals/tasks_processor_signals.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../tasks_processor_base/tasks_processor_base.hpp \ 7 | ../tasks_processor_timers/tasks_processor_timers.hpp \ 8 | ../tasks_processor_network/tasks_processor_network.hpp \ 9 | ../tasks_processor_multithread/tasks_processor_multithread.hpp \ 10 | tasks_processor_signals.hpp 11 | 12 | SOURCES += main.cpp 13 | LIBS += -lboost_thread -lboost_system 14 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_timers/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Almost all the code for this recipe 3 | // is in this header file 4 | #include "tasks_processor_timers.hpp" 5 | using namespace tp_timers; 6 | 7 | 8 | // Part of tasks_processor class from 9 | // tasks_processor_timers.hpp, that must be defined 10 | // Somewhere in source file 11 | tasks_processor& tasks_processor::get() { 12 | static tasks_processor proc; 13 | return proc; 14 | } 15 | 16 | void test_func(int& i) { 17 | i = 1; 18 | tasks_processor::get().stop(); 19 | } 20 | 21 | void test_func1() { 22 | throw std::logic_error("It works!"); 23 | } 24 | 25 | #include 26 | 27 | int main () { 28 | const int seconds_to_wait = 3; 29 | int i = 0; 30 | 31 | tasks_processor::get().run_after( 32 | boost::posix_time::seconds(seconds_to_wait), 33 | boost::bind(&test_func, boost::ref(i)) 34 | ); 35 | 36 | tasks_processor::get().run_at(boost::posix_time::from_time_t(time(NULL) + 1), &test_func1); 37 | 38 | int t1 = static_cast(time(NULL)); 39 | assert(i == 0); 40 | 41 | tasks_processor::get().start(); 42 | assert(i == 1); 43 | int t2 = static_cast(time(NULL)); 44 | assert(t2 - t1 >= seconds_to_wait); // seconds_to_wait seconds elapsed 45 | } 46 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_timers/tasks_processor_timers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) 5 | # pragma once 6 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 7 | 8 | #include "../tasks_processor_base/tasks_processor_base.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace detail { 17 | typedef boost::asio::deadline_timer::duration_type duration_type; 18 | 19 | template 20 | struct timer_task: public task_wrapped { 21 | private: 22 | typedef task_wrapped base_t; 23 | boost::shared_ptr timer_; 24 | 25 | public: 26 | template 27 | explicit timer_task( 28 | boost::asio::io_service& ios, 29 | const Time& duration_or_time, 30 | const Functor& task_unwrapped) 31 | : base_t(task_unwrapped) 32 | , timer_(boost::make_shared( 33 | boost::ref(ios), duration_or_time 34 | )) 35 | {} 36 | 37 | void push_task() const { 38 | timer_->async_wait(*this); 39 | } 40 | 41 | void operator()(const boost::system::error_code& error) const { 42 | if (!error) { 43 | base_t::operator()(); 44 | } else { 45 | std::cerr << error << '\n'; 46 | } 47 | } 48 | }; 49 | } // namespace detail 50 | 51 | namespace detail { 52 | template 53 | inline timer_task make_timer_task( 54 | boost::asio::io_service& ios, 55 | const Time& duration_or_time, 56 | const Functor& task_unwrapped) 57 | { 58 | return timer_task(ios, duration_or_time, task_unwrapped); 59 | } 60 | } 61 | 62 | namespace tp_timers { 63 | 64 | class tasks_processor: public tp_base::tasks_processor { 65 | public: 66 | static tasks_processor& get(); 67 | 68 | typedef boost::asio::deadline_timer::duration_type duration_type; 69 | 70 | template 71 | void run_after(duration_type duration, const Functor& f) { 72 | detail::make_timer_task(ios_, duration, f) 73 | .push_task(); 74 | } 75 | 76 | typedef boost::asio::deadline_timer::time_type time_type; 77 | 78 | template 79 | void run_at(time_type time, const Functor& f) { 80 | detail::make_timer_task(ios_, time, f) 81 | .push_task(); 82 | } 83 | }; 84 | 85 | } // namespace tp_timers 86 | 87 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 88 | -------------------------------------------------------------------------------- /Chapter06/tasks_processor_timers/tasks_processor_timers.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | 6 | HEADERS += \ 7 | ../tasks_processor_base/tasks_processor_base.hpp \ 8 | tasks_processor_timers.hpp 9 | 10 | SOURCES += main.cpp 11 | LIBS += -lboost_system -lboost_thread 12 | -------------------------------------------------------------------------------- /Chapter07/Chapter07.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | case_conv \ 5 | regex_match \ 6 | regex_replace \ 7 | format \ 8 | string_algo \ 9 | iterator_range \ 10 | string_ref 11 | -------------------------------------------------------------------------------- /Chapter07/case_conv/case_conv.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/case_conv/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | std::string str1 = "Thanks for reading me!"; 3 | std::string str2 = "Thanks for reading ME!"; 4 | 5 | #include 6 | void method1() { assert( 7 | boost::iequals(str1, str2) 8 | );} 9 | 10 | #include 11 | #include 12 | void method2() { assert( 13 | 14 | str1.size() == str2.size() && std::equal( 15 | str1.begin(), 16 | str1.end(), 17 | str2.begin(), 18 | boost::is_iequal() 19 | ) 20 | 21 | );} 22 | 23 | #include 24 | void method3() { 25 | 26 | std::string str1_low = boost::to_lower_copy(str1); 27 | std::string str2_low = boost::to_lower_copy(str2); 28 | assert(str1_low == str2_low); 29 | 30 | } 31 | 32 | #include 33 | void method4() { 34 | 35 | std::string str1_up = boost::to_upper_copy(str1); 36 | std::string str2_up = boost::to_upper_copy(str2); 37 | assert(str1_up == str2_up); 38 | 39 | } 40 | 41 | #include 42 | void method5() { 43 | 44 | boost::to_lower(str1); 45 | boost::to_lower(str2); 46 | assert(str1 == str2); 47 | 48 | } 49 | 50 | int main() { 51 | method1(); 52 | method2(); 53 | method3(); 54 | method4(); 55 | method5(); 56 | 57 | // On some platforms std::locale::classic() works 58 | // faster than std::locale() 59 | boost::iequals(str1, str2, std::locale::classic()); 60 | } 61 | -------------------------------------------------------------------------------- /Chapter07/format/format.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/format/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class i_hold_some_internals { 5 | int i; 6 | std::string s; 7 | char c; 8 | // ... 9 | public: 10 | i_hold_some_internals() 11 | : i(100) 12 | , s("Reader") 13 | , c('!') 14 | {} 15 | 16 | // fmt prameter must contain the following: 17 | // $1$ for outputting integer 'i' 18 | // $2$ for outputting string 's' 19 | // $3$ for outputting charecter 'c' 20 | std::string to_string(const std::string& format_specifier) const { 21 | boost::format f(format_specifier); 22 | unsigned char flags = boost::io::all_error_bits; 23 | flags ^= boost::io::too_many_args_bit; 24 | f.exceptions(flags); 25 | return (f % i % s % c).str(); 26 | } 27 | }; 28 | 29 | int main() { 30 | i_hold_some_internals class_instance; 31 | 32 | std::cout << class_instance.to_string( 33 | "Hello, dear %2%! " 34 | "Did you read the book for %1% %% %3%\n" 35 | ); 36 | 37 | std::cout << class_instance.to_string( 38 | "%1% == %1% && %1%%% != %1%\n\n" 39 | ); 40 | 41 | // Outputs 'Reader' 42 | std::cout << class_instance.to_string("%2%\n\n"); 43 | 44 | try { 45 | class_instance.to_string("%1% %2% %3% %4% %5%\n"); 46 | assert(false); 47 | } catch (const std::exception& e) { 48 | // boost::io::too_few_args exception must be catched 49 | std::cout << e.what() << '\n'; 50 | } 51 | } // int main() 52 | -------------------------------------------------------------------------------- /Chapter07/iterator_range/iterator_range.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/iterator_range/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | const char str[] 8 | = "This is a long long character array." 9 | "Please split this character array to sentences!" 10 | "Do you know, that sentences are separated using period, " 11 | "exclamation mark and question mark? :-)" 12 | ; 13 | 14 | typedef boost::split_iterator split_iter_t; 15 | split_iter_t sentences = boost::make_split_iterator(str, 16 | boost::algorithm::token_finder(boost::is_any_of("?!.")) 17 | ); 18 | 19 | 20 | for (unsigned int i = 1; !sentences.eof(); ++sentences, ++i) { 21 | boost::iterator_range range = *sentences; 22 | std::cout << "Sentence #" << i << " : \t" << range << '\n'; 23 | std::cout << "Sentence has " << range.size() << " characters.\n"; 24 | std::cout 25 | << "Sentence has " 26 | << std::count(range.begin(), range.end(), ' ') 27 | << " whitespaces.\n\n"; 28 | } // end of for(...) loop 29 | } // end of main() 30 | -------------------------------------------------------------------------------- /Chapter07/regex_match/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::cout 6 | << "Available regex syntaxes:\n" 7 | << "\t[0] Perl\n" 8 | << "\t[1] Perl case insensitive\n" 9 | << "\t[2] POSIX extended\n" 10 | << "\t[3] POSIX extended case insensitive\n" 11 | << "\t[4] POSIX basic\n" 12 | << "\t[5] POSIX basic case insensitive\n" 13 | << "Choose regex syntax: "; 14 | 15 | boost::regex::flag_type flag; 16 | switch (std::cin.get()) { 17 | case '0': flag = boost::regex::perl; 18 | break; 19 | 20 | case '1': flag = boost::regex::perl|boost::regex::icase; 21 | break; 22 | 23 | case '2': flag = boost::regex::extended; 24 | break; 25 | 26 | case '3': flag = boost::regex::extended|boost::regex::icase; 27 | break; 28 | 29 | case '4': flag = boost::regex::basic; 30 | break; 31 | 32 | case '5': flag = boost::regex::basic|boost::regex::icase; 33 | break; 34 | default: 35 | std::cout << "Incorrect number of regex syntax. Exiting... \n"; 36 | return -1; 37 | } 38 | // Disabling exceptions 39 | flag |= boost::regex::no_except; 40 | 41 | // Restoring std::cin 42 | std::cin.ignore(); 43 | std::cin.clear(); 44 | 45 | std::string regex, str; 46 | do { 47 | std::cout << "Input regex: "; 48 | if (!std::getline(std::cin, regex) || regex.empty()) { 49 | return 0; 50 | } 51 | 52 | // Without `boost::regex::no_except`flag this 53 | // constructor may throw 54 | const boost::regex e(regex, flag); 55 | if (e.status()) { 56 | std::cout << "Incorrect regex pattern!\n"; 57 | continue; 58 | } 59 | 60 | std::cout << "String to match: "; 61 | while (std::getline(std::cin, str) && !str.empty()) { 62 | bool matched = boost::regex_match(str, e); 63 | std::cout << (matched ? "MATCH\n" : "DOES NOT MATCH\n"); 64 | std::cout << "String to match: "; 65 | } // end of `while (std::getline(std::cin, str))` 66 | 67 | std::cout << '\n'; 68 | 69 | // Restoring std::cin 70 | std::cin.ignore(); 71 | std::cin.clear(); 72 | } while (1); 73 | } // int main() 74 | -------------------------------------------------------------------------------- /Chapter07/regex_match/regex_match.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_regex 7 | -------------------------------------------------------------------------------- /Chapter07/regex_replace/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::cout 6 | << "Available regex syntaxes:\n" 7 | << "\t[0] Perl\n" 8 | << "\t[1] Perl case insensitive\n" 9 | << "\t[2] POSIX extended\n" 10 | << "\t[3] POSIX extended case insensitive\n" 11 | << "\t[4] POSIX basic\n" 12 | << "\t[5] POSIX basic case insensitive\n" 13 | << "Choose regex syntax: "; 14 | 15 | boost::regex::flag_type flag; 16 | switch (std::cin.get()) { 17 | case '0': flag = boost::regex::perl; 18 | break; 19 | 20 | case '1': flag = boost::regex::perl|boost::regex::icase; 21 | break; 22 | 23 | case '2': flag = boost::regex::extended; 24 | break; 25 | 26 | case '3': flag = boost::regex::extended|boost::regex::icase; 27 | break; 28 | 29 | case '4': flag = boost::regex::basic; 30 | break; 31 | 32 | case '5': flag = boost::regex::basic|boost::regex::icase; 33 | break; 34 | default: 35 | std::cout << "Incorrect number of regex syntax. Exiting... \n"; 36 | return -1; 37 | } 38 | // Disabling exceptions 39 | flag |= boost::regex::no_except; 40 | 41 | // Restoring std::cin 42 | std::cin.ignore(); 43 | std::cin.clear(); 44 | 45 | std::string regex, str, replace_string; 46 | do { 47 | std::cout << "\nInput regex: "; 48 | if (!std::getline(std::cin, regex)) { 49 | return 0; 50 | } 51 | 52 | // Without `boost::regex::no_except`flag this 53 | // constructor may throw 54 | const boost::regex e(regex, flag); 55 | if (e.status()) { 56 | std::cout << "Incorrect regex pattern!\n"; 57 | continue; 58 | } 59 | 60 | std::cout << "String to match: "; 61 | while (std::getline(std::cin, str) && !str.empty()) { 62 | boost::smatch results; 63 | bool matched = regex_search(str, results, e); 64 | if (matched) { 65 | std::cout << "MATCH: "; 66 | std::copy( 67 | results.begin() + 1, 68 | results.end(), 69 | std::ostream_iterator( std::cout, ", ") 70 | ); 71 | 72 | std::cout << "\nReplace pattern: "; 73 | if ( 74 | std::getline(std::cin, replace_string) 75 | && !replace_string.empty()) 76 | { 77 | //std::cout << "RESULT: " << boost::regex_replace(str, e, replace_string); 78 | std::cout << "RESULT: " << results.format(replace_string); 79 | } else { 80 | // Restoring std::cin 81 | std::cin.ignore(); 82 | std::cin.clear(); 83 | } 84 | } else { // `if (matched) ` 85 | std::cout << "DOES NOT MATCH"; 86 | } 87 | 88 | std::cout << "\nString to match: "; 89 | } // end of `while (std::getline(std::cin, str))` 90 | 91 | std::cout << '\n'; 92 | 93 | // Restoring std::cin 94 | std::cin.ignore(); 95 | std::cin.clear(); 96 | } while (1); 97 | } // int main() 98 | -------------------------------------------------------------------------------- /Chapter07/regex_replace/regex_replace.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_regex 7 | -------------------------------------------------------------------------------- /Chapter07/string_algo/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | const std::string str = "Hello, hello, dear Reader."; 4 | 5 | #include 6 | void erasing_examples() { 7 | namespace ba = boost::algorithm; 8 | 9 | std::cout << "\n erase_all_copy :" << ba::erase_all_copy(str, ","); 10 | std::cout << "\n erase_first_copy :" << ba::erase_first_copy(str, ","); 11 | std::cout << "\n erase_last_copy :" << ba::erase_last_copy(str, ","); 12 | std::cout << "\n ierase_all_copy :" << ba::ierase_all_copy(str, "hello"); 13 | std::cout << "\n ierase_nth_copy :" << ba::ierase_nth_copy(str, ",", 1); 14 | } 15 | 16 | #include 17 | void replacing_examples() { 18 | namespace ba = boost::algorithm; 19 | 20 | std::cout << "\n replace_all_copy :" << ba::replace_all_copy(str, ",", "!"); 21 | std::cout << "\n replace_first_copy :" << ba::replace_first_copy(str, ",", "!"); 22 | std::cout << "\n replace_head_copy :" << ba::replace_head_copy(str, 6, "Whaaaaaaa!"); 23 | } 24 | 25 | int main() { 26 | erasing_examples(); 27 | replacing_examples(); 28 | 29 | } // int main() 30 | -------------------------------------------------------------------------------- /Chapter07/string_algo/string_algo.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/string_ref/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string between_str(const std::string& input, char starts, char ends) { 5 | std::string::const_iterator pos_beg 6 | = std::find(input.begin(), input.end(), starts); 7 | if (pos_beg == input.end()) { 8 | return std::string(); // Empty 9 | } 10 | ++ pos_beg; 11 | 12 | std::string::const_iterator pos_end 13 | = std::find(pos_beg, input.end(), ends); 14 | 15 | return std::string(pos_beg, pos_end); 16 | } 17 | 18 | #include 19 | boost::string_ref between( 20 | const boost::string_ref& input, 21 | char starts, 22 | char ends) 23 | { 24 | boost::string_ref::const_iterator pos_beg 25 | = std::find(input.cbegin(), input.cend(), starts); 26 | if (pos_beg == input.cend()) { 27 | return boost::string_ref(); // Empty 28 | } 29 | ++ pos_beg; 30 | 31 | boost::string_ref::const_iterator pos_end 32 | = std::find(pos_beg, input.cend(), ends); 33 | // ... 34 | if (pos_end == input.cend()) { 35 | return boost::string_ref(pos_beg, input.end() - pos_beg); 36 | } 37 | 38 | return boost::string_ref(pos_beg, pos_end - pos_beg); 39 | } // end of between 40 | 41 | #include 42 | void string_ref_init_examples() { 43 | boost::string_ref r0("^_^"); 44 | 45 | std::string O_O("O__O"); 46 | boost::string_ref r1 = O_O; 47 | 48 | std::vector chars_vec(10, '#'); 49 | boost::string_ref r2(&chars_vec.front(), chars_vec.size()); 50 | 51 | (void)r0; 52 | (void)r1; 53 | (void)r2; 54 | } 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | void string_ref_algorithms_examples() { 62 | boost::string_ref r("O_O"); 63 | // Finding symbol 64 | std::find(r.cbegin(), r.cend(), '_'); 65 | 66 | // Will print 'o_o' 67 | boost::to_lower_copy(std::ostream_iterator(std::cout), r); 68 | std::cout << '\n'; 69 | 70 | // Will print 'O_O' 71 | std::cout << r << '\n'; 72 | 73 | // Will print '^_^' 74 | boost::replace_all_copy( 75 | std::ostream_iterator(std::cout), r, "O", "^" 76 | ); 77 | std::cout << '\n'; 78 | 79 | r = "100"; 80 | assert(boost::lexical_cast(r) == 100); 81 | } 82 | 83 | int main() { 84 | std::cout << between("Getting expression (between brackets)", '(', ')') << '\n'; 85 | 86 | std::string s("(expression)"); 87 | std::cout << between(s, '(', ')') << '\n'; 88 | 89 | string_ref_init_examples(); 90 | string_ref_algorithms_examples(); 91 | } 92 | -------------------------------------------------------------------------------- /Chapter07/string_ref/string_ref.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/Chapter08.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | vector_of_types \ 5 | manipulating_vector_of_types \ 6 | result_of_c++11 \ 7 | higher_order_metafunctions \ 8 | lazy \ 9 | tuple_to_string \ 10 | splitting_tuple 11 | -------------------------------------------------------------------------------- /Chapter08/higher_order_metafunctions/higher_order_metafunctions.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter08/higher_order_metafunctions/main.cpp: -------------------------------------------------------------------------------- 1 | typedef void(*function_t)(int); 2 | 3 | function_t higher_order_function1(); 4 | void higher_order_function2(function_t f); 5 | function_t higher_order_function3(function_t f); 6 | 7 | template 8 | struct coalesce; 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | template 15 | struct coalesce { 16 | typedef typename boost::mpl::apply::type type1; 17 | typedef typename boost::mpl::apply::type type2; 18 | 19 | typedef typename boost::mpl::if_< 20 | boost::is_same< boost::mpl::false_, type1>, 21 | type2, 22 | type1 23 | >::type type; 24 | }; 25 | 26 | 27 | #include 28 | #include 29 | 30 | using boost::mpl::_1; 31 | using boost::mpl::_2; 32 | 33 | typedef coalesce< 34 | boost::mpl::true_, 35 | boost::mpl::true_, 36 | boost::mpl::not_<_1>, 37 | boost::mpl::not_<_1> 38 | >::type res1_t; 39 | BOOST_STATIC_ASSERT((!res1_t::value)); 40 | 41 | typedef coalesce< 42 | boost::mpl::true_, 43 | boost::mpl::false_, 44 | boost::mpl::not_<_1>, 45 | boost::mpl::not_<_1> 46 | >::type res2_t; 47 | BOOST_STATIC_ASSERT((res2_t::value)); 48 | 49 | typedef coalesce< 50 | boost::mpl::false_, 51 | boost::mpl::false_, 52 | boost::mpl::not_<_1>, 53 | boost::mpl::not_ > 54 | >::type res3_t; 55 | BOOST_STATIC_ASSERT((res3_t::value)); 56 | 57 | typedef coalesce< 58 | boost::mpl::false_, 59 | boost::mpl::true_, 60 | boost::mpl::not_<_1>, 61 | boost::mpl::not_ > 62 | >::type res4_t; 63 | BOOST_STATIC_ASSERT((res4_t::value)); 64 | 65 | 66 | 67 | #include 68 | #include 69 | int main() { 70 | // std::cerr << typeid(res2_t).name() << '\n'; 71 | } 72 | -------------------------------------------------------------------------------- /Chapter08/lazy/lazy.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/lazy/main.cpp: -------------------------------------------------------------------------------- 1 | struct fallback; 2 | 3 | template < 4 | class Func, 5 | class Param, 6 | class Cond, 7 | class Fallback = fallback> 8 | struct apply_if; 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | //#define USE_INCORRECT_APPLY_IF 15 | #ifndef USE_INCORRECT_APPLY_IF 16 | 17 | template 18 | struct apply_if { 19 | typedef typename boost::mpl::apply< 20 | Cond, Param 21 | >::type condition_t; 22 | typedef boost::mpl::apply applied_type; 23 | 24 | typedef typename boost::mpl::eval_if_c< 25 | condition_t::value, 26 | applied_type, 27 | boost::mpl::identity 28 | >::type type; 29 | }; 30 | 31 | #else // USE_INCORRECT_APPLY_IF 32 | 33 | template 34 | struct apply_if { 35 | typedef boost::mpl::apply condition_t; 36 | 37 | // Incorrect, metafunction is evaluated when `::type` called 38 | typedef typename boost::mpl::apply::type applied_type; 39 | 40 | typedef typename boost::mpl::if_c< 41 | condition_t::value, 42 | applied_type, 43 | boost::mpl::identity 44 | >::type type; 45 | }; 46 | 47 | #endif // USE_INCORRECT_APPLY_IF 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | using boost::mpl::_1; 55 | using boost::mpl::_2; 56 | 57 | typedef apply_if< 58 | boost::make_unsigned<_1>, 59 | int, 60 | boost::is_integral<_1> 61 | >::type res1_t; 62 | BOOST_STATIC_ASSERT(( 63 | boost::is_same::value 64 | )); 65 | 66 | // will fail with static assert somewhere deep in implementation 67 | // of boost::make_unsigned<_1> if we won't be evaluating function lazy. 68 | typedef apply_if< 69 | boost::make_unsigned<_1>, 70 | float, 71 | boost::is_integral<_1> 72 | >::type res2_t; 73 | BOOST_STATIC_ASSERT(( 74 | boost::is_same::value 75 | )); 76 | 77 | /* 78 | // eval_if_c implementation example 79 | 80 | template 81 | struct eval_if_c { 82 | typedef typename if_c::type f_; 83 | typedef typename f_::type type; // call `::type` only for one parameter 84 | }; 85 | 86 | */ 87 | 88 | int main() { 89 | } 90 | -------------------------------------------------------------------------------- /Chapter08/manipulating_vector_of_types/main.cpp: -------------------------------------------------------------------------------- 1 | // Make unsigned 2 | struct unsigne; // No typo: `unsigned` is a keyword, we can not use it. 3 | 4 | // Make constant 5 | struct constant; 6 | 7 | // Otherwise we do not change type 8 | struct no_change; 9 | 10 | // we'll need this at step 3 11 | #include 12 | #include 13 | #include 14 | 15 | // we'll need this at step 4 16 | #include 17 | #include 18 | #include 19 | 20 | // we'll need this at step 5 21 | #include 22 | 23 | template 24 | struct do_modifications { 25 | BOOST_STATIC_ASSERT((boost::is_same< 26 | typename boost::mpl::size::type, 27 | typename boost::mpl::size::type 28 | >::value)); 29 | 30 | BOOST_STATIC_ASSERT(( 31 | boost::mpl::size::type::value 32 | == 33 | boost::mpl::size::type::value 34 | )); 35 | 36 | typedef boost::mpl::if_< 37 | boost::is_same, 38 | boost::make_unsigned, 39 | boost::mpl::if_< 40 | boost::is_same, 41 | boost::add_const, 42 | boost::mpl::_1 43 | > 44 | > binary_operator_t; 45 | 46 | // >::type binary_operator_t; // INCORRECT! 47 | 48 | typedef typename boost::mpl::transform< 49 | Types, 50 | Modifiers, 51 | binary_operator_t 52 | >::type type; 53 | }; 54 | 55 | /* 56 | void boost_mpl_transform_pseoudocode() { 57 | 58 | vector result; 59 | for (std::size_t i = 0; i < Types.size(); ++i) { 60 | result.push_back( 61 | binary_operator_t(Types[i], Modifiers[i]) 62 | ); 63 | } 64 | return result; 65 | } 66 | */ 67 | 68 | #include 69 | typedef boost::mpl::vector modifiers; 70 | typedef boost::mpl::vector types; 71 | 72 | typedef do_modifications::type result_type; 73 | 74 | #include 75 | 76 | BOOST_STATIC_ASSERT((boost::is_same< 77 | boost::mpl::at_c::type, 78 | unsigned int 79 | >::value)); 80 | 81 | BOOST_STATIC_ASSERT((boost::is_same< 82 | boost::mpl::at_c::type, 83 | char 84 | >::value)); 85 | 86 | BOOST_STATIC_ASSERT((boost::is_same< 87 | boost::mpl::at_c::type, 88 | const short 89 | >::value)); 90 | 91 | BOOST_STATIC_ASSERT((boost::is_same< 92 | boost::mpl::at_c::type, 93 | unsigned long 94 | >::value)); 95 | 96 | // GCC4.6 has problems with variadic templates: 97 | // # sorry, unimplemented: cannot expand ‘T ...’ into a fixed-length argument list 98 | // NOTE: Clang compiler defines __GNUC__ 99 | #if defined(__clang__) || !(defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 7)) 100 | 101 | #include 102 | #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES 103 | 104 | template 105 | struct vt_example { 106 | typedef typename boost::mpl::vector type; 107 | }; 108 | 109 | BOOST_STATIC_ASSERT((boost::is_same< 110 | boost::mpl::at_c::type, 0>::type, 111 | int 112 | >::value)); 113 | 114 | #endif 115 | 116 | #endif // gcc4.6 workaround 117 | 118 | #include 119 | #include 120 | int main() { 121 | std::cout << typeid(boost::mpl::size::type).name() << '\n'; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /Chapter08/manipulating_vector_of_types/manipulating_vector_of_types.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter08/result_of_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | template 2 | auto my_function_cpp11(const T1& v1, const T2& v2) 3 | -> decltype(v1 + v2) 4 | { 5 | return v1 + v2; 6 | } 7 | 8 | #include 9 | 10 | struct s1 {}; 11 | struct s2 {}; 12 | struct s3 {}; 13 | 14 | inline s3 operator + (const s1& /*v1*/, const s2& /*v2*/) { 15 | return s3(); 16 | } 17 | 18 | inline s3 operator + (const s2& /*v1*/, const s1& /*v2*/) { 19 | return s3(); 20 | } 21 | 22 | #include 23 | namespace result_of { 24 | 25 | template 26 | struct my_function_cpp03 { 27 | typedef typename boost::common_type::type type; 28 | }; 29 | 30 | template <> 31 | struct my_function_cpp03 { 32 | typedef s3 type; 33 | }; 34 | 35 | template <> 36 | struct my_function_cpp03 { 37 | typedef s3 type; 38 | }; 39 | } // namespace result_of 40 | 41 | template 42 | inline typename result_of::my_function_cpp03::type 43 | my_function_cpp03(const T1& v1, const T2& v2) 44 | { 45 | return v1 + v2; 46 | } 47 | 48 | int main() { 49 | s1 v1; 50 | s2 v2; 51 | 52 | my_function_cpp11(v1, v2); 53 | my_function_cpp11(v1, v2); 54 | assert(my_function_cpp11('\0', 1) == 1); 55 | 56 | my_function_cpp03(v1, v2); 57 | my_function_cpp03(v2, v1); 58 | assert(my_function_cpp03('\0', 1) == 1); 59 | } 60 | -------------------------------------------------------------------------------- /Chapter08/result_of_c++11/result_of_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter08/splitting_tuple/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | typename boost::fusion::result_of::remove_if< 6 | const Sequence, 7 | boost::is_arithmetic 8 | >::type get_nonarithmetics(const Sequence& seq) 9 | { 10 | return boost::fusion::remove_if< 11 | boost::is_arithmetic 12 | >(seq); 13 | } 14 | 15 | template 16 | typename boost::fusion::result_of::remove_if< 17 | const Sequence, 18 | boost::mpl::not_< boost::is_arithmetic > 19 | >::type get_arithmetics(const Sequence& seq) 20 | { 21 | return boost::fusion::remove_if< 22 | boost::mpl::not_< boost::is_arithmetic > 23 | >(seq); 24 | } 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | int main() { 31 | 32 | typedef boost::fusion::vector< 33 | int, boost::blank, boost::blank, float 34 | > tup1_t; 35 | tup1_t tup1(8, boost::blank(), boost::blank(), 0.0); 36 | 37 | boost::fusion::vector res_na 38 | = get_nonarithmetics(tup1); 39 | boost::fusion::vector res_a = get_arithmetics(tup1); 40 | assert(boost::fusion::at_c<0>(res_a) == 8); 41 | 42 | 43 | (void)res_na; 44 | } 45 | 46 | #include 47 | #include 48 | #include 49 | template 50 | struct make_nonconst: boost::mpl::transform< 51 | Sequence, 52 | boost::remove_const 53 | > {}; 54 | 55 | typedef boost::fusion::vector< 56 | const int, const boost::blank, boost::blank 57 | > type1; 58 | typedef make_nonconst::type nc_type; 59 | 60 | BOOST_STATIC_ASSERT((boost::is_same< 61 | boost::fusion::result_of::value_at_c::type, 62 | int 63 | >::value)); 64 | 65 | BOOST_STATIC_ASSERT((boost::is_same< 66 | boost::fusion::result_of::value_at_c::type, 67 | boost::blank 68 | >::value)); 69 | 70 | BOOST_STATIC_ASSERT((boost::is_same< 71 | boost::fusion::result_of::value_at_c::type, 72 | boost::blank 73 | >::value)); 74 | -------------------------------------------------------------------------------- /Chapter08/splitting_tuple/splitting_tuple.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/tuple_to_string/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | struct stringize_functor: boost::noncopyable { 6 | private: 7 | std::string& result; 8 | 9 | public: 10 | explicit stringize_functor(std::string& res) 11 | : result(res) 12 | {} 13 | 14 | template 15 | void operator()(const T& v) const { 16 | result += boost::lexical_cast(v); 17 | } 18 | }; 19 | 20 | #include 21 | template 22 | std::string stringize(const Sequence& seq) { 23 | std::string result; 24 | boost::fusion::for_each(seq, stringize_functor(result)); 25 | return result; 26 | } 27 | 28 | struct cat{}; 29 | std::ostream& operator << (std::ostream& os, const cat& ) { 30 | return os << "Meow! "; 31 | } 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | void tuple_example() { 38 | boost::tuple tup(1, 2, "Meow"); 39 | assert(boost::get<0>(tup) == 1); 40 | assert(boost::get<2>(tup) == "Meow"); 41 | } 42 | 43 | #include 44 | #include 45 | void fusion_tuple_example() { 46 | boost::fusion::vector tup(1, 2, "Meow"); 47 | assert(boost::fusion::at_c<0>(tup) == 1); 48 | assert(boost::fusion::at_c<2>(tup) == "Meow"); 49 | } 50 | 51 | #include 52 | std::string stringize_tup2_example() { 53 | boost::tuple tup2(cat(), 0, "_0"); 54 | 55 | std::string result; 56 | 57 | // Instead of 58 | // boost::fusion::for_each(seq, stringize_functor(result)); 59 | // there'll be the following: 60 | { 61 | stringize_functor functor(result); 62 | functor(boost::fusion::at_c<0>(tup2)); 63 | functor(boost::fusion::at_c<1>(tup2)); 64 | functor(boost::fusion::at_c<2>(tup2)); 65 | } 66 | return result; 67 | } 68 | 69 | 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | int main() { 76 | tuple_example(); 77 | fusion_tuple_example(); 78 | stringize_tup2_example(); 79 | 80 | boost::fusion::vector tup1(cat(), 0, "_0"); 81 | boost::tuple tup2(cat(), 0, "_0"); 82 | std::pair cats; 83 | boost::array many_cats; 84 | 85 | std::cout << stringize(tup1) << '\n' 86 | << stringize(tup2) << '\n' 87 | << stringize(cats) << '\n' 88 | << stringize(many_cats) << '\n'; 89 | } 90 | -------------------------------------------------------------------------------- /Chapter08/tuple_to_string/tuple_to_string.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/vector_of_types/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | template < 3 | class T0 = boost::mpl::na, // boost::mpl::na == n.a. == not available 4 | class T1 = boost::mpl::na, 5 | class T2 = boost::mpl::na, 6 | class T3 = boost::mpl::na, 7 | class T4 = boost::mpl::na, 8 | class T5 = boost::mpl::na, 9 | class T6 = boost::mpl::na, 10 | class T7 = boost::mpl::na, 11 | class T8 = boost::mpl::na, 12 | class T9 = boost::mpl::na 13 | > 14 | struct variant; 15 | 16 | 17 | #include 18 | template < 19 | class T0, class T1, class T2, class T3, class T4, 20 | class T5, class T6, class T7, class T8, class T9 21 | > 22 | struct variant { 23 | typedef boost::mpl::vector types; 24 | }; 25 | 26 | #include 27 | struct declared{ unsigned char data[4096]; }; 28 | struct non_declared; 29 | 30 | typedef variant< 31 | volatile int, 32 | const int, 33 | const long, 34 | declared, 35 | non_declared, 36 | std::string 37 | >::types types; 38 | 39 | #include 40 | #include 41 | BOOST_STATIC_ASSERT((!boost::mpl::empty::value)); 42 | 43 | 44 | #include 45 | #include 46 | BOOST_STATIC_ASSERT((boost::is_same< 47 | non_declared, 48 | boost::mpl::at_c::type 49 | >::value)); 50 | 51 | 52 | #include 53 | BOOST_STATIC_ASSERT((boost::is_same< 54 | boost::mpl::back::type, 55 | std::string 56 | >::value)); 57 | 58 | #include 59 | #include 60 | typedef boost::mpl::transform< 61 | types, 62 | boost::remove_cv 63 | >::type noncv_types; 64 | 65 | #include 66 | typedef boost::mpl::unique< 67 | noncv_types, 68 | boost::is_same 69 | >::type unique_types; 70 | 71 | #include 72 | BOOST_STATIC_ASSERT((boost::mpl::size::value == 5)); 73 | 74 | // Without this we'll get an error: 75 | // use of undefined type 'non_declared' 76 | struct non_declared{}; 77 | 78 | #include 79 | typedef boost::mpl::transform< 80 | unique_types, 81 | boost::mpl::sizeof_ 82 | >::type sizes_types; 83 | 84 | #include 85 | typedef boost::mpl::max_element::type max_size_type; 86 | 87 | BOOST_STATIC_ASSERT(max_size_type::type::value == sizeof(declared)); 88 | 89 | 90 | #include 91 | #include 92 | #include 93 | #include 94 | 95 | void foo2() { 96 | typedef int type; 97 | std::vector types; 98 | // ... 99 | std::unique(types.begin(), types.end(), boost::bind(std::equal_to(), _1, _2)); 100 | } 101 | 102 | #include 103 | #include 104 | 105 | #include 106 | #include 107 | 108 | template 109 | int foo_size() { 110 | return boost::mpl::size::value; 111 | } 112 | 113 | int main() { 114 | typedef boost::mpl::vector vector1_type; 115 | assert(foo_size() == 3); 116 | 117 | foo2(); 118 | std::cout << typeid(sizes_types).name(); 119 | /* 120 | struct boost::mpl::vector< 121 | struct boost::mpl::size_t<4>, 122 | struct boost::mpl::size_t<4>, 123 | struct boost::mpl::size_t<4096>, 124 | struct boost::mpl::size_t<1>, 125 | struct boost::mpl::size_t<32> 126 | > 127 | */ 128 | } 129 | 130 | -------------------------------------------------------------------------------- /Chapter08/vector_of_types/vector_of_types.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/Chapter09.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | hash \ 5 | unordered \ 6 | bimap \ 7 | multiindex \ 8 | slist_and_pool \ 9 | flat \ 10 | 11 | -------------------------------------------------------------------------------- /Chapter09/bimap/bimap.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/bimap/main.cpp: -------------------------------------------------------------------------------- 1 | void example1(); 2 | void example2(); 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | typedef boost::bimap< 10 | std::string, 11 | boost::bimaps::multiset_of 12 | > name_id_type; 13 | 14 | name_id_type name_id; 15 | 16 | // Inserting keys <-> values 17 | name_id.insert(name_id_type::value_type( 18 | "John Snow", 1 19 | )); 20 | 21 | name_id.insert(name_id_type::value_type( 22 | "Vasya Pupkin", 2 23 | )); 24 | 25 | name_id.insert(name_id_type::value_type( 26 | "Antony Polukhin", 3 27 | )); 28 | 29 | // Same person as "Antony Polukhin" 30 | name_id.insert(name_id_type::value_type( 31 | "Anton Polukhin", 3 32 | )); 33 | 34 | 35 | std::cout << "Left:\n"; 36 | typedef name_id_type::left_const_iterator left_const_iterator; 37 | for (left_const_iterator it = name_id.left.begin(), 38 | iend = name_id.left.end(); 39 | it!= iend; 40 | ++it) 41 | { 42 | std::cout << it->first << " <=> " << it->second << '\n'; 43 | } 44 | 45 | std::cout << "\nRight:\n"; 46 | typedef name_id_type::right_const_iterator right_const_iterator; 47 | for (right_const_iterator it = name_id.right.begin(), 48 | iend = name_id.right.end(); 49 | it!= iend; 50 | ++it) 51 | { 52 | std::cout << it->first << " <=> " << it->second << '\n'; 53 | } 54 | 55 | assert(name_id.left.find("John Snow")->second == 1); 56 | assert(name_id.right.find(2)->second == "Vasya Pupkin"); 57 | assert( 58 | name_id.find(name_id_type::value_type( 59 | "Anton Polukhin", 3 60 | )) != name_id.end() 61 | ); 62 | 63 | example1(); 64 | example2(); 65 | } 66 | 67 | #include 68 | typedef boost::bimap< 69 | boost::bimaps::set_of, 70 | boost::bimaps::multiset_of 71 | > name_id_type; 72 | 73 | #include 74 | void example1() { 75 | name_id_type name_id; 76 | 77 | std::map key1; // == name_id.left 78 | std::multimap key2; // == name_id.right 79 | } 80 | 81 | #include 82 | #include 83 | 84 | typedef boost::bimap< 85 | boost::bimaps::unordered_set_of, 86 | boost::bimaps::unordered_multiset_of 87 | > hash_name_id_type; 88 | 89 | void example2() { 90 | hash_name_id_type name_id; 91 | 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Chapter09/flat/flat.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/flat/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void test_flat() { 5 | boost::container::flat_set set; 6 | set.reserve(4096); 7 | 8 | for (int i = 0; i < 4000; ++i) { 9 | set.insert(i); 10 | } 11 | 12 | // 5.1 13 | assert(set.lower_bound(500) - set.lower_bound(100) == 400); 14 | 15 | // 5.2 16 | set.erase(0); 17 | 18 | // 5.3 19 | set.erase(5000); 20 | 21 | // 5.4 22 | assert(std::lower_bound(set.cbegin(), set.cend(), 900000) == set.cend()); 23 | 24 | // 5.5 25 | assert( 26 | set.lower_bound(100) + 400 27 | == 28 | set.find(500) 29 | ); 30 | } 31 | 32 | int main() { 33 | test_flat(); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Chapter09/hash/hash.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/hash/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::size_t test_default() { 5 | // Constants 6 | const std::size_t ii_max = 200000000; 7 | const std::string s( 8 | "Long long long string that " 9 | "will be used in tests to compare " 10 | "speed of equality comparisons." 11 | ); 12 | 13 | // Making some data, that will be 14 | // used in comparisons 15 | const T data1[] = { 16 | T(s), 17 | T(s + s), 18 | T(s + ". Whooohooo"), 19 | T(std::string("")) 20 | }; 21 | 22 | const T data2[] = { 23 | T(s), 24 | T(s + s), 25 | T(s + ". Whooohooo"), 26 | T(std::string("")) 27 | }; 28 | 29 | const std::size_t data_dimensions = sizeof(data1) / sizeof(data1[0]); 30 | 31 | std::size_t matches = 0u; 32 | for (std::size_t ii = 0; ii < ii_max; ++ii) { 33 | for (std::size_t i = 0; i < data_dimensions; ++i) { 34 | for (std::size_t j = 0; j < data_dimensions; ++j) { 35 | if (data1[i] == data2[j]) { 36 | ++ matches; 37 | } 38 | } 39 | } 40 | } 41 | 42 | return matches; 43 | } 44 | 45 | 46 | 47 | 48 | #include 49 | 50 | struct string_hash_fast { 51 | typedef std::size_t comp_type; 52 | 53 | const comp_type comparison_; 54 | const std::string str_; 55 | 56 | explicit string_hash_fast(const std::string& s) 57 | : comparison_( 58 | boost::hash()(s) 59 | ) 60 | , str_(s) 61 | {} 62 | }; 63 | 64 | inline bool operator == (const string_hash_fast& s1, const string_hash_fast& s2) { 65 | return s1.comparison_ == s2.comparison_ && s1.str_ == s2.str_; 66 | } 67 | 68 | inline bool operator != (const string_hash_fast& s1, const string_hash_fast& s2) { 69 | return !(s1 == s2); 70 | } 71 | 72 | // Shall be in namespace of string_hash_fast class 73 | inline std::size_t hash_value(const string_hash_fast& v) { 74 | return v.comparison_; 75 | } 76 | 77 | #include 78 | int main(int argc, char* argv[]) { 79 | if (argc < 2) { 80 | assert( 81 | test_default() 82 | == 83 | test_default() 84 | ); 85 | return 0; 86 | } 87 | 88 | switch (argv[1][0]) { 89 | case 'h': 90 | std::cout << "HASH matched: " 91 | << test_default(); 92 | break; 93 | case 's': 94 | std::cout << "STD matched: " 95 | << test_default(); 96 | break; 97 | default: 98 | assert(false); 99 | return -2; 100 | } 101 | 102 | std::cout << '\n'; 103 | assert( 104 | boost::hash()(string_hash_fast("test")) 105 | == 106 | boost::hash()("test") 107 | ); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /Chapter09/multiindex/multiindex.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/slist_and_pool/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | void test_lists(); 7 | 8 | 9 | 10 | typedef boost::fast_pool_allocator allocator_t; 11 | typedef boost::container::slist slist_t; 12 | 13 | void list_specific(slist_t& list, slist_t::iterator it) { 14 | typedef slist_t::iterator iterator; 15 | 16 | // Erasing element 776 17 | assert( *(++iterator(it)) == 776); 18 | assert(*it == 777); 19 | list.erase_after(it); 20 | assert(*it == 777); 21 | assert( *(++iterator(it)) == 775); 22 | 23 | list.clear(); 24 | assert(list.empty()); 25 | 26 | // Freeing memory: slist rebinds allocator_t and allocates 27 | // nodes of the slist, not just ints. 28 | boost::singleton_pool< 29 | boost::fast_pool_allocator_tag, 30 | sizeof(slist_t::stored_allocator_type::value_type) 31 | >::release_memory(); 32 | } 33 | 34 | #include 35 | typedef std::list stdlist_t; 36 | void list_specific(stdlist_t& list, stdlist_t::iterator it) { 37 | // Erasing element 776 38 | ++it; 39 | assert( *it == 776); 40 | it = list.erase(it); 41 | assert(*it == 775); 42 | } 43 | 44 | void test_slist() { 45 | test_lists(); 46 | } 47 | 48 | void test_list() { 49 | test_lists >(); 50 | } 51 | 52 | template 53 | void test_lists() { 54 | typedef ListT list_t; 55 | 56 | // Inserting 1000000 zeros 57 | list_t list(1000000, 0); 58 | 59 | for (int i = 0; i < 1000; ++i) { 60 | list.insert(list.begin(), i); 61 | } 62 | 63 | // Searching for some value 64 | typedef typename list_t::iterator iterator; 65 | iterator it = std::find(list.begin(), list.end(), 777); 66 | assert(it != list.end()); 67 | 68 | // Erasing some values 69 | for (int i = 0; i < 100; ++i) { 70 | list.pop_front(); 71 | } 72 | 73 | // Iterator still valid and points to same value 74 | assert(it != list.end()); 75 | assert(*it == 777); 76 | 77 | // Inserting more values 78 | for (int i = -100; i < 10; ++i) { 79 | list.insert(list.begin(), i); 80 | } 81 | 82 | // Iterator still valid and points to same value 83 | assert(it != list.end()); 84 | assert(*it == 777); 85 | 86 | list_specific(list, it); 87 | } 88 | 89 | #include 90 | int main(int argc, char* argv[]) { 91 | if (argc < 2) { 92 | test_slist(); 93 | test_list(); 94 | return 0; 95 | } 96 | 97 | switch(argv[1][0]) { 98 | case 's': std::cout << "slist_t: "; test_slist(); break; 99 | case 'l': std::cout << "std::list: "; test_list(); break; 100 | default: 101 | std::cout << "Use 's' for testsing slist performance " 102 | "and 'l' for testsing std::list performance."; 103 | } 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /Chapter09/slist_and_pool/slist_and_pool.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter09/unordered/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | void example() { 11 | boost::unordered_set strings; 12 | 13 | strings.insert("This"); 14 | strings.insert("is"); 15 | strings.insert("an"); 16 | strings.insert("example"); 17 | 18 | assert(strings.find("is") != strings.cend()); 19 | } 20 | 21 | #include 22 | template 23 | void output_example() { 24 | T strings; 25 | 26 | strings.insert("CZ"); strings.insert("CD"); 27 | strings.insert("A"); strings.insert("B"); 28 | 29 | std::copy( 30 | strings.begin(), 31 | strings.end(), 32 | std::ostream_iterator(std::cout, " ") 33 | ); 34 | } 35 | 36 | 37 | template 38 | std::size_t test_default() { 39 | // Constants 40 | const std::size_t ii_max = 20000000; 41 | const std::string s("Test string"); 42 | 43 | T map; 44 | 45 | for (std::size_t ii = 0; ii < ii_max; ++ii) { 46 | map[s + boost::lexical_cast(ii)] = ii; 47 | } 48 | 49 | // Inserting once more 50 | for (std::size_t ii = 0; ii < ii_max; ++ii) { 51 | map[s + boost::lexical_cast(ii)] = ii; 52 | } 53 | 54 | return map.size(); 55 | } 56 | 57 | struct my_type { 58 | int val1_; 59 | std::string val2_; 60 | }; 61 | 62 | inline bool operator == (const my_type& v1, const my_type& v2) { 63 | return v1.val1_ == v2.val1_ && v1.val2_ == v2.val2_; 64 | } 65 | 66 | std::size_t hash_value(const my_type& v) { 67 | std::size_t ret = 0u; 68 | 69 | boost::hash_combine(ret, v.val1_); 70 | boost::hash_combine(ret, v.val2_); 71 | 72 | return ret; 73 | } 74 | 75 | 76 | int main(int argc, char* argv[]) { 77 | if (argc < 2) { 78 | example(); 79 | 80 | std::cout << "boost::unordered_set : "; 81 | output_example >(); 82 | std::cout << "\nstd::set : "; 83 | output_example >(); 84 | std::cout << '\n'; 85 | 86 | boost::unordered_set mt; 87 | mt.insert(my_type()); 88 | return 0; 89 | } 90 | 91 | switch (argv[1][0]) { 92 | case 'h': std::cout << "HASH matched: " << test_default< boost::unordered_map >(); break; 93 | case 's': std::cout << "STD matched: " << test_default >(); break; 94 | default: assert(false); return -2; 95 | } 96 | 97 | std::cout << '\n'; 98 | } 99 | 100 | -------------------------------------------------------------------------------- /Chapter09/unordered/unordered.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter10/Chapter10.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | int128 \ 5 | no_rtti \ 6 | extern_template \ 7 | constexpr_c++11 \ 8 | noexcept_c++11 \ 9 | export_import \ 10 | my_library \ 11 | version \ 12 | 13 | export_import.depends = my_library 14 | -------------------------------------------------------------------------------- /Chapter10/constexpr_c++11/constexpr_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/constexpr_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if !defined(BOOST_NO_CXX11_CONSTEXPR) \ 4 | && !defined(BOOST_NO_CXX11_HDR_ARRAY) 5 | 6 | template 7 | constexpr int get_size(const T& val) { 8 | return val.size() * sizeof(typename T::value_type); 9 | } 10 | 11 | template 12 | struct integral_constant { 13 | BOOST_STATIC_CONSTEXPR T value = Value; 14 | BOOST_CONSTEXPR operator T() const { 15 | return this->value; 16 | } 17 | }; 18 | 19 | char array[integral_constant()]; 20 | 21 | #else 22 | #error "This code requires C++11 constexpr and std::array" 23 | #endif 24 | 25 | 26 | #include 27 | #include 28 | int main() { 29 | 30 | std::array arr; 31 | assert(get_size(arr) == 5 * sizeof(short)); 32 | 33 | 34 | unsigned char data[get_size(arr)]; 35 | 36 | assert(sizeof(array) == 10); 37 | (void)data; 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /Chapter10/export_import/export_import.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # There is a line in parent project: 6 | # export_import.depends = my_library 7 | # that forces `my_library` project 8 | # build before building this project. 9 | 10 | SOURCES += main.cpp 11 | HEADERS += ../my_library/my_library.hpp 12 | DEFINES += MY_LIBRARY_LINK_DYNAMIC 13 | LIBS += -L../my_library -lmy_library 14 | 15 | # We compile-in the path to the library 16 | unix|macos { 17 | QMAKE_LFLAGS+=-Wl,-rpath=../my_library/ 18 | QMAKE_LFLAGS+=-Wl,-rpath=Chapter10/my_library/ 19 | } 20 | -------------------------------------------------------------------------------- /Chapter10/export_import/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../my_library/my_library.hpp" 2 | #include 3 | 4 | int main() { 5 | assert(foo() == 0); 6 | bar b; 7 | try { 8 | b.meow(); 9 | assert(false); 10 | } catch (const bar_exception&) {} 11 | } 12 | -------------------------------------------------------------------------------- /Chapter10/extern_template/extern_template.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp header.hpp source.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/extern_template/header.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_BOOK_CHAPTER10_EXTERN_TEMPLATES 2 | #define BOOST_BOOK_CHAPTER10_EXTERN_TEMPLATES 3 | 4 | // Somewhere in header file 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef BOOST_NO_CXX11_EXTERN_TEMPLATE 13 | 14 | extern template class boost::variant< 15 | boost::blank, 16 | int, 17 | std::string, 18 | double 19 | >; 20 | 21 | #endif 22 | 23 | typedef boost::variant< 24 | boost::blank, 25 | int, 26 | std::string, 27 | double 28 | > variant_type; 29 | 30 | #endif // #ifndef BOOST_BOOK_CHAPTER10_EXTERN_TEMPLATES 31 | 32 | -------------------------------------------------------------------------------- /Chapter10/extern_template/main.cpp: -------------------------------------------------------------------------------- 1 | #include "header.hpp" 2 | 3 | int main() { 4 | variant_type v1(0), v2, v3(1.1); 5 | 6 | (void)v1; 7 | (void)v2; 8 | (void)v3; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /Chapter10/extern_template/source.cpp: -------------------------------------------------------------------------------- 1 | // Header with 'extern template' 2 | #include "header.hpp" 3 | 4 | #ifndef BOOST_NO_CXX11_EXTERN_TEMPLATE 5 | template class boost::variant< 6 | boost::blank, 7 | int, 8 | std::string, 9 | double 10 | >; 11 | #endif 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter10/int128/int128.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter10/int128/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace project { 4 | 5 | #ifdef BOOST_HAS_INT128 6 | typedef boost::int128_type int_t; 7 | typedef boost::uint128_type uint_t; 8 | 9 | inline int_t mul(int_t v1, int_t v2, int_t v3) { 10 | return v1 * v2 * v3; 11 | } 12 | 13 | #else // BOOST_NO_LONG_LONG 14 | 15 | #ifdef BOOST_NO_LONG_LONG 16 | #error "This code requires at least int64_t support" 17 | #endif 18 | 19 | struct int_t { boost::long_long_type hi, lo; }; 20 | struct uint_t { boost::ulong_long_type hi, lo; }; 21 | 22 | inline int_t mul(int_t v1, int_t v2, int_t v3) { 23 | // Some hand written math 24 | // ... 25 | return int_t(); 26 | } 27 | 28 | #endif // BOOST_NO_LONG_LONG 29 | 30 | } // namespace project 31 | 32 | int main() { 33 | using namespace project; 34 | 35 | mul(int_t(), int_t(), int_t()); 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Chapter10/my_library/my_library.cpp: -------------------------------------------------------------------------------- 1 | #define MY_LIBRARY_COMPILATION 2 | #include "my_library.hpp" 3 | 4 | int MY_LIBRARY_API foo() { 5 | // Implementation 6 | // ... 7 | return 0; 8 | } 9 | 10 | int bar::meow() const { 11 | throw bar_exception(); 12 | } 13 | -------------------------------------------------------------------------------- /Chapter10/my_library/my_library.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MY_LIBRARY_HPP 2 | #define MY_LIBRARY_HPP 3 | 4 | #include 5 | 6 | #if defined(MY_LIBRARY_LINK_DYNAMIC) 7 | # if defined(MY_LIBRARY_COMPILATION) 8 | # define MY_LIBRARY_API BOOST_SYMBOL_EXPORT 9 | # else 10 | # define MY_LIBRARY_API BOOST_SYMBOL_IMPORT 11 | # endif 12 | #else 13 | # define MY_LIBRARY_API 14 | #endif 15 | 16 | int MY_LIBRARY_API foo(); 17 | class MY_LIBRARY_API bar { 18 | public: 19 | /* ... */ 20 | int meow() const; 21 | }; 22 | 23 | #include 24 | struct BOOST_SYMBOL_VISIBLE bar_exception 25 | : public std::exception 26 | {}; 27 | 28 | #endif // MY_LIBRARY_HPP 29 | -------------------------------------------------------------------------------- /Chapter10/my_library/my_library.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # We are NOT building an executable 6 | TEMPLATE -= app 7 | 8 | # ... we are building a library 9 | TEMPLATE = lib 10 | 11 | # Sources and headers of that library 12 | SOURCES += my_library.cpp 13 | HEADERS += my_library.hpp 14 | 15 | # Making a dynamic library 16 | DEFINES += MY_LIBRARY_LINK_DYNAMIC 17 | 18 | -------------------------------------------------------------------------------- /Chapter10/no_rtti/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #if !defined(BOOST_NO_RTTI) \ 5 | && !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) 6 | 7 | #include 8 | using std::type_index; 9 | 10 | template 11 | type_index type_id() { 12 | return typeid(T); 13 | } 14 | 15 | #else 16 | 17 | #include 18 | #include // std::basic_ostream 19 | 20 | struct type_index { 21 | const char * name_; 22 | 23 | explicit type_index(const char* name) 24 | : name_(name) 25 | {} 26 | 27 | const char* name() const { return name_; } 28 | }; 29 | 30 | inline bool operator == (const type_index& v1, const type_index& v2) { 31 | return !std::strcmp(v1.name_, v2.name_); 32 | } 33 | 34 | inline bool operator != (const type_index& v1, const type_index& v2) { 35 | // '!!' to supress warnings 36 | return !!std::strcmp(v1.name_, v2.name_); 37 | } 38 | 39 | template 40 | inline std::basic_ostream& operator << (std::basic_ostream& os, const type_index& t) { 41 | return os << t.name_; 42 | } 43 | 44 | #include 45 | template 46 | inline type_index type_id() { 47 | return type_index(BOOST_CURRENT_FUNCTION); 48 | } 49 | 50 | #endif 51 | 52 | #include 53 | #include 54 | int main() { 55 | assert(type_id() == type_id()); 56 | assert(type_id() != type_id()); 57 | 58 | std::cout << type_id().name(); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /Chapter10/no_rtti/no_rtti.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/noexcept_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class move_nothrow { 4 | // Some class class members go here 5 | // ... 6 | public: 7 | move_nothrow() BOOST_NOEXCEPT {} 8 | move_nothrow(move_nothrow&&) BOOST_NOEXCEPT 9 | // : members initialization 10 | // ... 11 | {} 12 | 13 | move_nothrow& operator=(move_nothrow&&) BOOST_NOEXCEPT { 14 | // Implementation 15 | // ... 16 | return *this; 17 | } 18 | 19 | move_nothrow(const move_nothrow&); 20 | move_nothrow& operator=(const move_nothrow&); 21 | }; 22 | 23 | 24 | #include 25 | int main() { 26 | 27 | std::vector v(10); 28 | v.push_back(move_nothrow()); 29 | 30 | } 31 | 32 | // In header file 33 | int foo() BOOST_NOEXCEPT; 34 | 35 | 36 | // In source file 37 | int foo() BOOST_NOEXCEPT { 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter10/noexcept_c++11/noexcept_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/version/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int to_int(const char* str, std::size_t length); 3 | 4 | #include 5 | #include 6 | 7 | #if (BOOST_VERSION >= 105200) 8 | 9 | int to_int(const char* str, std::size_t length) { 10 | return boost::lexical_cast(str, length); 11 | } 12 | 13 | #else 14 | 15 | int to_int(const char* str, std::size_t length) { 16 | return boost::lexical_cast( 17 | std::string(str, length) 18 | ); 19 | } 20 | 21 | #endif 22 | 23 | #include 24 | int main() { 25 | assert(to_int("10000000", 3) == 100); 26 | } 27 | -------------------------------------------------------------------------------- /Chapter10/version/version.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter11/Chapter11.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | listing_files \ 5 | erasing_files \ 6 | interprocess_basics \ 7 | interprocess_queue \ 8 | interprocess_pointers \ 9 | reading_files \ 10 | coroutines 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter11/coroutines/coroutines.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | LIBS += -lboost_context 8 | LIBS += -lboost_coroutine -lboost_thread -lboost_system 9 | -------------------------------------------------------------------------------- /Chapter11/erasing_files/erasing_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_system -lboost_filesystem 7 | -------------------------------------------------------------------------------- /Chapter11/erasing_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | boost::system::error_code error; 8 | 9 | boost::filesystem::create_directories("dir/subdir", error); 10 | assert(!error); 11 | 12 | std::ofstream ofs("dir/subdir/file.txt"); 13 | ofs << "Boost.Filesystem is fun!"; 14 | assert(ofs); 15 | ofs.close(); 16 | 17 | boost::filesystem::create_directory_symlink("dir/subdir", "symlink", error); 18 | if (!error) { 19 | std::cerr << "Symlink created\n"; 20 | assert(boost::filesystem::exists("symlink/file.txt")); 21 | } else { 22 | std::cerr << "Failed to create a symlink\n"; 23 | boost::filesystem::remove("dir/subdir/file.txt", error); 24 | assert(!error); 25 | } /*if (!error)*/ 26 | } /*main*/ 27 | -------------------------------------------------------------------------------- /Chapter11/interprocess_basics/interprocess_basics.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/interprocess_basics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef boost::atomic atomic_t; 6 | #if (BOOST_ATOMIC_INT_LOCK_FREE != 2) 7 | #error "This code requires lock-free boost::atomic" 8 | #endif 9 | 10 | //#include 11 | //typedef std::atomic atomic_t; 12 | 13 | 14 | 15 | int main() { 16 | boost::interprocess::managed_shared_memory 17 | segment(boost::interprocess::open_or_create, "shm1-cache", 1024); 18 | 19 | atomic_t& atomic 20 | = *segment.find_or_construct //1 21 | ("shm-counter") // 2 22 | (0) // 3 23 | ; 24 | 25 | std::cout << "I have index " << ++ atomic 26 | << "\nPress any key..."; 27 | std::cin.get(); 28 | 29 | int snapshot = -- atomic; 30 | if (!snapshot) { 31 | segment.destroy("shm1-counter"); 32 | boost::interprocess::shared_memory_object 33 | ::remove("shm-cache"); 34 | } 35 | } /*main*/ 36 | -------------------------------------------------------------------------------- /Chapter11/interprocess_pointers/interprocess_pointers.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/interprocess_pointers/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct with_pointer { 4 | int* pointer_; 5 | // ... 6 | int value_holder_; 7 | }; 8 | 9 | 10 | #include 11 | 12 | struct correct_struct { 13 | boost::interprocess::offset_ptr pointer_; 14 | // ... 15 | int value_holder_; 16 | }; 17 | 18 | 19 | #include 20 | 21 | template 22 | void test() { 23 | typedef T correct_struct; 24 | static const int ethalon_value = 777; 25 | 26 | boost::interprocess::managed_shared_memory 27 | segment(boost::interprocess::open_or_create, "segment", 4096); 28 | 29 | correct_struct* ptr = 30 | segment.find("structure").first; 31 | 32 | if (ptr) { 33 | std::cout << "Structure found\n"; 34 | assert(*ptr->pointer_ == ethalon_value); 35 | segment.destroy("structure"); 36 | } else { 37 | std::cout << "Creating structure\n"; 38 | correct_struct& ref = *segment.construct("structure")(); 39 | ref.pointer_ = &ref.value_holder_; 40 | assert(ref.pointer_ == &ref.value_holder_); 41 | assert(*ref.pointer_ == ref.value_holder_); 42 | ref.value_holder_ = ethalon_value; 43 | assert(*ref.pointer_ == ethalon_value); 44 | } 45 | } 46 | 47 | 48 | #include 49 | 50 | int main() { 51 | test(); // Shall be OK 52 | //test(); // Shall fail 53 | } 54 | -------------------------------------------------------------------------------- /Chapter11/interprocess_queue/interprocess_queue.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/listing_files/listing_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_system -lboost_filesystem 7 | -------------------------------------------------------------------------------- /Chapter11/listing_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | boost::filesystem::directory_iterator begin("./"); 6 | boost::filesystem::directory_iterator end; 7 | 8 | for (; begin != end; ++ begin) { 9 | /* 10 | boost::filesystem::file_status fs = 11 | boost::filesystem::status(*begin); 12 | */ 13 | 14 | boost::filesystem::file_status fs = 15 | begin->status(); 16 | 17 | switch (fs.type()) { 18 | case boost::filesystem::regular_file: 19 | std::cout << "FILE "; 20 | break; 21 | case boost::filesystem::symlink_file: 22 | std::cout << "SYMLINK "; 23 | break; 24 | case boost::filesystem::directory_file: 25 | std::cout << "DIRECTORY "; 26 | break; 27 | default: 28 | std::cout << "OTHER "; 29 | break; 30 | } 31 | 32 | if (fs.permissions() & boost::filesystem::owner_write) { 33 | std::cout << "W "; 34 | } else { 35 | std::cout << " "; 36 | } 37 | 38 | std::cout << begin->path() << '\n'; 39 | //std::cout << *begin << '\n'; 40 | } /*for*/ 41 | } /*main*/ 42 | -------------------------------------------------------------------------------- /Chapter11/reading_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char* argv[]) { 11 | static const std::size_t filesize = 1024 * 1024 * 128; 12 | const char filename[] = "test_file.txt"; 13 | 14 | assert(argc >= 2); 15 | switch (argv[1][0]) { 16 | case 'c': { 17 | // Not effective, but this is not a place that we measure 18 | std::ofstream f(filename, std::ofstream::binary); 19 | std::fill_n( 20 | std::ostream_iterator(f), 21 | filesize - 1, 22 | '\3' 23 | ); 24 | 25 | f << '\1'; 26 | } 27 | break; 28 | 29 | case 'm': { 30 | std::cout << "mapped_region:"; 31 | const boost::interprocess::mode_t mode = boost::interprocess::read_only; 32 | boost::interprocess::file_mapping fm(filename, mode); 33 | boost::interprocess::mapped_region region(fm, mode, 0, 0); 34 | //region.advise(boost::interprocess::mapped_region::advice_sequential); 35 | 36 | const char* begin = reinterpret_cast(region.get_address()); 37 | const char* pos = std::find(begin, begin + region.get_size(), '\1'); 38 | assert(pos == begin + filesize - 1); 39 | assert(region.get_size() == filesize); 40 | } 41 | break; 42 | 43 | case 'r': { 44 | std::cout << "ifstream:"; 45 | static const std::size_t kilobyte = 1024; 46 | std::ifstream f(filename, std::ifstream::binary); 47 | char c[kilobyte]; 48 | char* begin = c; 49 | char* end = c + sizeof(c); 50 | char* pos; 51 | 52 | size_t i = 0; 53 | for (; i < filesize / kilobyte; ++i) { 54 | f.read(c, kilobyte); 55 | pos = std::find(begin, end, '\1'); 56 | if (pos != end) 57 | break; 58 | } 59 | 60 | assert(pos - begin == kilobyte - 1); 61 | assert(i == filesize / kilobyte - 1); 62 | } 63 | break; 64 | 65 | case 'a': { 66 | std::cout << "C:"; 67 | static const std::size_t kilobyte = 1024; 68 | FILE* f = fopen(filename, "rb"); 69 | char c[kilobyte]; 70 | char* begin = c; 71 | char* end = c + sizeof(c); 72 | char* pos; 73 | 74 | size_t i = 0; 75 | for (; i < filesize / kilobyte; ++i) { 76 | std::size_t res = fread(c, 1, kilobyte, f); 77 | pos = std::find(begin, end, '\1'); 78 | if (pos != end) 79 | break; 80 | (void)res; 81 | } 82 | 83 | assert(pos - begin == kilobyte - 1); 84 | assert(i == filesize / kilobyte - 1); 85 | fclose (f); 86 | } 87 | break; 88 | 89 | default: 90 | assert(false); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Chapter11/reading_files/reading_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter12/Chapter12.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | graph \ 5 | graph_vis \ 6 | random \ 7 | math \ 8 | testing \ 9 | testing_advanced \ 10 | gil \ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Chapter12/gil/gil.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | LIBS += -lpng 8 | -------------------------------------------------------------------------------- /Chapter12/gil/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | struct negate { 8 | typedef void result_type; // required 9 | 10 | template 11 | void operator()(const View& source) const { 12 | 13 | // Code formatting is shifted left to fit page width 14 | boost::gil::gil_function_requires< 15 | boost::gil::ImageViewConcept 16 | >(); 17 | 18 | typedef typename View::value_type value_type; 19 | typedef typename boost::gil::channel_type::type channel_t; 20 | 21 | const std::size_t channels = boost::gil::num_channels::value; 22 | const channel_t max_val = (std::numeric_limits::max)(); 23 | 24 | for (unsigned int y = 0; y < source.height(); ++y) { 25 | for (unsigned int x = 0; x < source.width(); ++x) { 26 | for (unsigned int c = 0; c < channels; ++c) { 27 | source(x, y)[c] = max_val - source(x, y)[c]; 28 | } 29 | } 30 | } 31 | 32 | 33 | } 34 | }; // negate 35 | 36 | int main(int argc, char *argv[]) { 37 | if (argc < 2) { 38 | assert(false); 39 | } 40 | 41 | typedef boost::mpl::vector< 42 | boost::gil::gray8_image_t, 43 | boost::gil::gray16_image_t, 44 | boost::gil::rgb8_image_t, 45 | boost::gil::rgb16_image_t 46 | > img_types; 47 | 48 | std::string file_name(argv[1]); 49 | boost::gil::any_image source; 50 | boost::gil::png_read_image(file_name, source); 51 | 52 | boost::gil::apply_operation( 53 | view(source), 54 | negate() 55 | ); 56 | 57 | boost::gil::png_write_view("negate_" + file_name, const_view(source)); 58 | } 59 | -------------------------------------------------------------------------------- /Chapter12/graph/graph.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter12/graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef std::string vertex_t; 4 | 5 | typedef boost::adjacency_list< 6 | boost::vecS 7 | , boost::vecS 8 | , boost::bidirectionalS 9 | , vertex_t 10 | > graph_type; 11 | 12 | #include 13 | #include 14 | template 15 | void find_and_print(const GraphT& g, boost::string_ref name) { 16 | typedef typename boost::graph_traits 17 | ::vertex_iterator vert_it_t; 18 | vert_it_t it, end; 19 | boost::tie(it, end) = boost::vertices(g); 20 | 21 | typedef boost::graph_traits::vertex_descriptor desc_t; 22 | for (; it != end; ++ it) { 23 | desc_t desc = *it; 24 | if (boost::get(boost::vertex_bundle, g)[desc] == name.data()) { 25 | break; 26 | } 27 | } 28 | 29 | assert(it != end); 30 | std::cout << name << '\n'; 31 | } /* find_and_print */ 32 | 33 | int main() { 34 | graph_type graph; 35 | 36 | static const std::size_t vertex_count = 5; 37 | graph.m_vertices.reserve(vertex_count); 38 | /* 39 | C++ -> STL -> Boost -> C++ guru <- C 40 | */ 41 | 42 | typedef boost::graph_traits 43 | ::vertex_descriptor descriptor_t; 44 | descriptor_t cpp 45 | = boost::add_vertex(vertex_t("C++"), graph); 46 | descriptor_t stl 47 | = boost::add_vertex(vertex_t("STL"), graph); 48 | descriptor_t boost 49 | = boost::add_vertex(vertex_t("Boost"), graph); 50 | descriptor_t guru 51 | = boost::add_vertex(vertex_t("C++ guru"), graph); 52 | descriptor_t ansic 53 | = boost::add_vertex(vertex_t("C"), graph); 54 | 55 | BOOST_STATIC_ASSERT((boost::is_same::value)); 56 | 57 | boost::add_edge(cpp, stl, graph); 58 | boost::add_edge(stl, boost, graph); 59 | boost::add_edge(boost, guru, graph); 60 | boost::add_edge(ansic, guru, graph); 61 | 62 | 63 | find_and_print(graph, "Boost"); 64 | find_and_print(graph, "C++ guru"); 65 | } 66 | -------------------------------------------------------------------------------- /Chapter12/graph_vis/graph_vis.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter12/graph_vis/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef std::string vertex_t; 4 | 5 | typedef boost::adjacency_list< 6 | boost::vecS 7 | , boost::vecS 8 | , boost::bidirectionalS 9 | , vertex_t 10 | > graph_type; 11 | 12 | namespace detail { 13 | template 14 | class vertex_writer { 15 | const GraphT& g_; 16 | 17 | public: 18 | explicit vertex_writer(const GraphT& g) 19 | : g_(g) 20 | {} 21 | 22 | template 23 | void operator()(std::ostream& out, const VertexDescriptorT& d) const { 24 | out << " [label=\"" 25 | << boost::get(boost::vertex_bundle, g_)[d] 26 | << "\"]"; 27 | } 28 | }; // vertex_writer 29 | } // namespace detail 30 | 31 | #include 32 | std::ostream& operator<<(std::ostream& out, const graph_type& g) { 33 | detail::vertex_writer vw(g); 34 | boost::write_graphviz(out, g, vw); 35 | 36 | return out; 37 | } 38 | 39 | 40 | 41 | int main() { 42 | graph_type graph; 43 | 44 | static const std::size_t vertex_count = 5; 45 | graph.m_vertices.reserve(vertex_count); 46 | /* 47 | C++ -> STL -> Boost -> C++ guru <- C 48 | */ 49 | 50 | typedef boost::graph_traits::vertex_descriptor descriptor_t; 51 | descriptor_t cpp 52 | = boost::add_vertex(vertex_t("C++"), graph); 53 | descriptor_t stl 54 | = boost::add_vertex(vertex_t("STL"), graph); 55 | descriptor_t boost 56 | = boost::add_vertex(vertex_t("Boost"), graph); 57 | descriptor_t guru 58 | = boost::add_vertex(vertex_t("C++ guru"), graph); 59 | descriptor_t ansic 60 | = boost::add_vertex(vertex_t("C"), graph); 61 | 62 | BOOST_STATIC_ASSERT((boost::is_same::value)); 63 | 64 | boost::add_edge(cpp, stl, graph); 65 | boost::add_edge(stl, boost, graph); 66 | boost::add_edge(boost, guru, graph); 67 | boost::add_edge(ansic, guru, graph); 68 | 69 | std::cout << graph; 70 | } 71 | -------------------------------------------------------------------------------- /Chapter12/math/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void check_float_inputs(T value) { 6 | assert(!boost::math::isinf(value)); 7 | assert(!boost::math::isnan(value)); 8 | 9 | if (boost::math::signbit(value)) { 10 | value = boost::math::changesign(value); 11 | } 12 | 13 | // ... 14 | assert(value + (std::numeric_limits::epsilon)() >= static_cast(0)); 15 | } // check_float_inputs 16 | 17 | int main() { 18 | check_float_inputs(0.0); 19 | check_float_inputs(-110.0f); 20 | check_float_inputs(-11.0l); 21 | 22 | // Shall fail the `!boost::math::isinf(value)` assertion 23 | //check_float_inputs((std::numeric_limits::max)() * 2.0); 24 | 25 | 26 | // Shall fail the `!boost::math::isnan(value)` assertion 27 | //check_float_inputs(std::sqrt(-1.0)); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter12/math/math.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter12/random/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | static const std::string provider = 8 | #ifdef BOOST_WINDOWS 9 | "Microsoft Strong Cryptographic Provider" 10 | #else 11 | "/dev/urandom" 12 | #endif 13 | ; 14 | 15 | boost::random_device device(provider); 16 | boost::random::uniform_int_distribution random(1000); 17 | 18 | for (unsigned int i = 0; i < 10000; ++i) { 19 | std::cerr << random(device) << '\t'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter12/random/random.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | LIBS += -lboost_random -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter12/testing/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | struct foo { 3 | int val_; 4 | 5 | operator int() const; 6 | bool is_not_null() const; 7 | void throws() const; // throws(std::logic_error) 8 | }; 9 | 10 | #define BOOST_TEST_MODULE test_module_name 11 | #include 12 | 13 | BOOST_AUTO_TEST_CASE(test_no_1) { 14 | foo f1 = {1}, f2 = {2}; 15 | BOOST_CHECK(f1.is_not_null()); 16 | 17 | BOOST_CHECK_NE(f1, f2); 18 | 19 | BOOST_CHECK_THROW(f1.throws(), std::logic_error); 20 | } // BOOST_AUTO_TEST_CASE(test_no_1) 21 | 22 | BOOST_AUTO_TEST_CASE(test_no_2) { 23 | foo f1 = {1}, f2 = {2}; 24 | BOOST_REQUIRE_NE(f1, f2); 25 | // ... 26 | } // BOOST_AUTO_TEST_CASE(test_no_2) 27 | 28 | #define DO_NOT_FAIL 29 | #ifdef DO_NOT_FAIL 30 | foo::operator int() const { 31 | return val_; 32 | } 33 | 34 | bool foo::is_not_null() const { 35 | return !!val_; 36 | } 37 | 38 | void foo::throws() const { 39 | throw std::logic_error("Expected exception"); 40 | } 41 | 42 | #else 43 | 44 | foo::operator int() const { 45 | return 0; 46 | } 47 | 48 | bool foo::is_not_null() const { 49 | return !val_; 50 | } 51 | 52 | void foo::throws() const {} 53 | 54 | #endif // DO_NOT_FAIL 55 | -------------------------------------------------------------------------------- /Chapter12/testing/testing.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # Boost.Test works well only when we link against 8 | # static version of boost_unit_test_framework library 9 | LIBS += -static -lboost_unit_test_framework -lboost_system 10 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/developer1.cpp: -------------------------------------------------------------------------------- 1 | // developer1.cpp 2 | #include 3 | #include "foo.hpp" 4 | 5 | BOOST_AUTO_TEST_CASE(test_no_1) { 6 | // ... 7 | foo f1 = {1}, f2 = {2}; 8 | BOOST_CHECK(f1.is_not_null()); 9 | 10 | BOOST_CHECK_NE(f1, f2); 11 | 12 | BOOST_CHECK_THROW(f1.throws(), std::logic_error); 13 | } // BOOST_AUTO_TEST_CASE(test_no_1) 14 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/developer2.cpp: -------------------------------------------------------------------------------- 1 | // developer2.cpp 2 | #include 3 | #include "foo.hpp" 4 | 5 | BOOST_AUTO_TEST_CASE(test_no_2) { 6 | // ... 7 | foo f1 = {1}, f2 = {2}; 8 | BOOST_REQUIRE_NE(f1, f2); 9 | // ... 10 | } // BOOST_AUTO_TEST_CASE(test_no_2) 11 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/foo.cpp: -------------------------------------------------------------------------------- 1 | #include "foo.hpp" 2 | 3 | #define DO_NOT_FAIL 4 | #ifdef DO_NOT_FAIL 5 | foo::operator int() const { 6 | return val_; 7 | } 8 | 9 | bool foo::is_not_null() const { 10 | return !!val_; 11 | } 12 | 13 | void foo::throws() const { 14 | throw std::logic_error("Expected exception"); 15 | } 16 | 17 | #else 18 | 19 | foo::operator int() const { 20 | return 0; 21 | } 22 | 23 | bool foo::is_not_null() const { 24 | return !val_; 25 | } 26 | 27 | void foo::throws() const {} 28 | 29 | #endif // DO_NOT_FAIL 30 | 31 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/foo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_BOOK_CHAPTER12_FOO_HPP 2 | #define BOOST_BOOK_CHAPTER12_FOO_HPP 3 | 4 | #include 5 | struct foo { 6 | int val_; 7 | 8 | operator int() const; 9 | bool is_not_null() const; 10 | void throws() const; // throws(std::logic_error) 11 | }; 12 | 13 | #endif // BOOST_BOOK_CHAPTER12_FOO_HPP 14 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/main.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE test_module_name 2 | #include 3 | -------------------------------------------------------------------------------- /Chapter12/testing_advanced/testing_advanced.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp foo.cpp developer1.cpp developer2.cpp 6 | HEADERS += foo.hpp 7 | 8 | # Boost.Test works well only when we link against 9 | # static version of boost_unit_test_framework library 10 | LIBS += -static -lboost_unit_test_framework -lboost_system -ldl -lrt 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boost C++ Application Development Cookbook - Second Edition 2 | This is the code repository for [Boost C++ Application Development Cookbook - Second Edition](https://www.packtpub.com/application-development/boost-c-application-development-cookbook-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781787282247), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish. 3 | ## About the Book 4 | Beginning with the basics of Boost C++, you will move on to learn how the Boost libraries simplify application development. You will learn to convert data such as string to numbers, numbers to string, numbers to numbers and more. Managing resources will become a piece of cake. You’ll see what kind of work can be done at compile time and what Boost containers can do. You will learn everything for the development of high quality fast and portable applications. Write a program once and then you can use it on Linux, Windows, MacOS, Android operating systems. From manipulating images to graphs, directories, timers, files, networking – everyone will find an interesting topic. 5 | 6 | 7 | ## Instructions and Navigation 8 | All of the code is organized into folders. Each folder starts with a number followed by the application name. For example, Chapter02. 9 | 10 | 11 | 12 | The code will look like the following: 13 | ``` 14 | #include 15 | #include 16 | namespace opt = boost::program_options; 17 | int main(int argc, char *argv[]) 18 | ``` 19 | 20 | You need a modern C++ compiler, Boost libraries (any version will be OK, 1.65 or a more recent version is recommended), and QtCreator/qmake, or just navigate to http://apolukhin.github.io/Boost-Cookbook/ to run and experiment with examples online. 21 | 22 | ## Related Products 23 | * [Multithreading with C# Cookbook - Second Edition](https://www.packtpub.com/application-development/multithreading-c-cookbook-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781785881251) 24 | 25 | * [Boost.Asio C++ Network Programming - Second Edition](https://www.packtpub.com/networking-and-servers/boostasio-c-network-programming-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781785283079) 26 | 27 | * [WordPress Plugin Development Cookbook - Second Edition](https://www.packtpub.com/web-development/wordpress-plugin-development-cookbook-second-edition?utm_source=github&utm_medium=repository&utm_campaign=9781788291187) 28 | 29 | --------------------------------------------------------------------------------