├── .clang-format ├── .gitignore ├── 00_introduction.pdf ├── 01_value_semantics.pdf ├── 01_values ├── 01_01_basic_values.cpp ├── 01_02_basic_references.cpp ├── 01_03_lifecycle_creation_destruction.cpp ├── 01_04_lifecycle_copy_construction.cpp ├── 01_05_lifecycle_raii.cpp ├── 01_06_advanced_string.cpp ├── 01_07_advanced_string_move.cpp ├── 01_values.sln └── 01_values.vcxproj ├── 02_classes_and_interfaces.pdf ├── 02_classes_and_interfaces ├── 02_01_basic_interfaces.cpp ├── 02_02_function_size.cpp ├── 02_03_parameters_and_retvals.cpp ├── 02_04_return_smart_pointers.cpp ├── 02_05_class_hierarchies.cpp ├── 02_06_multiple_inheritance.cpp ├── 02_07_virtual_inheritance.cpp ├── 02_08_private_inheritance.cpp ├── 02_09_operator_overloading.cpp ├── 02_10_friends.cpp ├── 02_11_hidden_friends.cpp ├── 02_classes_and_interfaces.sln └── 02_classes_and_interfaces.vcxproj ├── 03_lambdas_and_algorithms.pdf ├── 03_lambdas_and_algorithms ├── 03_01_containers_sequence.cpp ├── 03_02_containers_associative.cpp ├── 03_03_containers_unordered.cpp ├── 03_04_iterators.cpp ├── 03_05_lambda_basics.cpp ├── 03_06_lambda_captures.cpp ├── 03_07_lambda_implementation.cpp ├── 03_08_alg_examples.cpp ├── 03_09_exec_policy_bench.cpp ├── 03_lambdas_and_algorithms.sln └── 03_lambdas_and_algorithms.vcxproj ├── 04_templates.pdf ├── 04_templates ├── 04_01_function_templates_basic.cpp ├── 04_02_template_parameter_categories.cpp ├── 04_03_template_parameter_packs.cpp ├── 04_04_template_arguments.cpp ├── 04_05_class_template_basics.cpp ├── 04_06_template_specialization.cpp ├── 04_07_class_template_arg_deduction.cpp ├── 04_08_variable_templates.cpp ├── 04_09_alias_templates.cpp ├── 04_10_two_phase_lookup.cpp ├── 04_11_parsing_hints.cpp ├── 04_templates.sln └── 04_templates.vcxproj ├── 05_keyword_safari.pdf ├── 05_keyword_safari ├── 05_01_storage_classes.cpp ├── 05_02_static_initialization.cpp ├── 05_03_cv_qualification.cpp ├── 05_04_static_members.cpp ├── 05_05_explicit_constructors.cpp ├── 05_06_member_ref_qualifiers.cpp ├── 05_07_mutable_data_members.cpp ├── 05_08_constexpr.cpp ├── 05_09_constevalinit.cpp ├── 05_keyword_safari.sln └── 05_keyword_safari.vcxproj ├── 06_advanced_templates.pdf ├── 06_advanced_templates ├── 06_01_simple_template_metafunction.cpp ├── 06_02_type_parameter.cpp ├── 06_03_type_result.cpp ├── 06_04_refactoring_conventions.cpp ├── 06_05_tuple_includes.cpp ├── 06_06_tuple_includes_prime.cpp ├── 06_07_dispatch.cpp ├── 06_08_decltype_declval.cpp ├── 06_09_sfinae.cpp ├── 06_10_crtp.cpp ├── 06_advanced_templates.sln └── 06_advanced_templates.vcxproj ├── 07_concepts.pdf ├── 07_concepts ├── 07_01_basic_sample.cpp ├── 07_02_syntax_options.cpp ├── 07_03_constrained_auto.cpp ├── 07_04_requires_expression.cpp ├── 07_05_requirements.cpp ├── 07_06_dispatch.cpp ├── 07_07_partial_order.cpp ├── 07_concepts.sln └── 07_concepts.vcxproj ├── 08_libraries.pdf ├── 08_libraries ├── 08_01_regex.cpp ├── 08_02_threads.cpp ├── 08_03_future_fs.cpp ├── 08_04_boost_format.cpp ├── 08_05_boost_bimap.cpp ├── 08_06_boost_operators.cpp ├── 08_07_boost_hana.cpp ├── 08_08_boost_program_options.cpp ├── 08_09_boost_log.cpp ├── 08_10_eigen.cpp ├── 08_libraries.sln └── 08_libraries.vcxproj └── README.md /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | 3 | AlignOperands: true 4 | AlignTrailingComments: true 5 | AllowShortBlocksOnASingleLine: true 6 | AllowShortCaseLabelsOnASingleLine: true 7 | AllowShortFunctionsOnASingleLine: Inline 8 | AllowShortIfStatementsOnASingleLine: true 9 | AllowShortLoopsOnASingleLine: false 10 | AlwaysBreakTemplateDeclarations: true 11 | BinPackArguments: true 12 | BinPackParameters: true 13 | BreakBeforeBinaryOperators: NonAssignment 14 | BreakBeforeBraces: Attach 15 | ColumnLimit: 160 16 | Cpp11BracedListStyle: true 17 | IndentCaseLabels: false 18 | IndentWidth: 4 19 | KeepEmptyLinesAtTheStartOfBlocks: false 20 | MaxEmptyLinesToKeep: 2 21 | NamespaceIndentation: Inner 22 | PointerAlignment: Left 23 | SpaceAfterCStyleCast: false 24 | SpaceBeforeParens: Never 25 | SpaceInEmptyParentheses: false 26 | SpacesBeforeTrailingComments: 1 27 | SpacesInAngles: false 28 | SpacesInCStyleCastParentheses: false 29 | SpacesInParentheses: false 30 | SpacesInSquareBrackets: false 31 | Standard: Cpp11 32 | TabWidth: 4 33 | UseTab: ForIndentation 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pptx 2 | *.filters 3 | *.user 4 | *.code-workspace 5 | *.7z 6 | 7 | out.txt 8 | 9 | .vs 10 | Debug 11 | x64 12 | exam* 13 | stream -------------------------------------------------------------------------------- /00_introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/00_introduction.pdf -------------------------------------------------------------------------------- /01_value_semantics.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/01_value_semantics.pdf -------------------------------------------------------------------------------- /01_values/01_01_basic_values.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | void f_int(int i) { 5 | i = 5; 6 | } 7 | 8 | class Cls { 9 | public: 10 | Cls(int i) : mem(i) { 11 | } 12 | int mem; 13 | }; 14 | 15 | void f_cls(Cls c) { 16 | c.mem = 5; 17 | } 18 | 19 | int main() { 20 | 21 | int x = 0; 22 | f_int(x); 23 | // what is the value of x? 24 | 25 | Cls c(0); 26 | f_cls(c); 27 | // what is the value of c.mem? 28 | 29 | // let's find out 30 | std::cout << "x: " << x << std::endl; 31 | std::cout << "c.mem: " << c.mem << std::endl; 32 | 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /01_values/01_02_basic_references.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // we read "int&" as "integer reference" 5 | void f_int(int& i) { 6 | i = 5; 7 | } 8 | 9 | class Cls { 10 | public: 11 | Cls(int i) : mem(i) { 12 | } 13 | int mem; 14 | }; 15 | 16 | // we read "Cls&" as "Cls reference" or "Reference to an object of type Cls" 17 | void f_cls(Cls& c) { 18 | c.mem = 5; 19 | } 20 | 21 | 22 | int main() { 23 | 24 | int x = 0; 25 | f_int(x); 26 | // what is the value of x? 27 | 28 | Cls c(0); 29 | f_cls(c); 30 | // what is the value of c.mem? 31 | 32 | // let's find out 33 | std::cout << "x: " << x << std::endl; 34 | std::cout << "c.mem: " << c.mem << std::endl; 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /01_values/01_03_lifecycle_creation_destruction.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // a "struct" is just like a class, except for default visibility being "public" 5 | struct C { 6 | int id; 7 | // constructor syntax 8 | C(int idParam) : id(idParam) { 9 | std::cout << "C " << id << " constructed" << std::endl; 10 | } 11 | // destructor syntax 12 | ~C() { 13 | std::cout << "C " << id << " destroyed" << std::endl; 14 | } 15 | }; 16 | 17 | 18 | int main() { 19 | 20 | C c1(1); 21 | 22 | C c2(2); 23 | 24 | { 25 | C c3(3); 26 | } 27 | 28 | if(C(4).id == 4) { 29 | C c(5); 30 | } 31 | 32 | C(6); 33 | 34 | C c(7); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /01_values/01_04_lifecycle_copy_construction.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | struct C { 5 | C() { 6 | std::cout << "C#" << this << " constructed" << std::endl; 7 | } 8 | ~C() { 9 | std::cout << "C#" << this << " destroyed" << std::endl; 10 | } 11 | // copy constructor syntax 12 | C(const C& from) { 13 | std::cout << "C#" << this << " constructed from C#" << &from << std::endl; 14 | } 15 | 16 | }; 17 | 18 | 19 | void takeC(C c) { 20 | std::cout << "We are in takeC" << std::endl; 21 | } 22 | 23 | C returnC() { 24 | std::cout << "We are in returnC" << std::endl; 25 | C c; 26 | std::cout << "We are leaving returnC" << std::endl; 27 | return c; 28 | } 29 | 30 | int main() { 31 | 32 | C val; 33 | 34 | C c101(val); 35 | 36 | takeC(val); 37 | 38 | returnC(); 39 | } 40 | -------------------------------------------------------------------------------- /01_values/01_05_lifecycle_raii.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() { 6 | bool doWorld = false; 7 | 8 | // block that deals with file writing 9 | { 10 | std::ofstream file("out.txt"); 11 | file << "Hello "; 12 | if(!doWorld) return 0; 13 | file << "World" << std::endl; 14 | } 15 | // file is now closed 16 | } 17 | 18 | 19 | /// C-style (and many other languages) comparison 20 | int badMain() { 21 | bool doWorld = false; 22 | 23 | // block that deals with file writing 24 | { 25 | FILE* f = fopen("out.txt", "w"); 26 | fprintf(f, "Hello "); 27 | if(!doWorld) return 0; 28 | fprintf(f, "World\n"); 29 | fclose(f); 30 | } 31 | // ??? 32 | } 33 | -------------------------------------------------------------------------------- /01_values/01_06_advanced_string.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | /// Note: 7 | /// this is a very C-style example, to make the concept of move semantics and r-value references easier to understand 8 | /// you shouldn't actually write your own string class, and you really shouldn't do it like this 9 | 10 | struct string 11 | { 12 | char* data; 13 | 14 | string(const char* p) { 15 | size_t size = strlen(p) + 1; 16 | data = new char[size]; 17 | memcpy(data, p, size); 18 | } 19 | 20 | ~string() { 21 | delete[] data; 22 | } 23 | 24 | string(const string& from) { 25 | std::cout << "Copying string" << std::endl; 26 | size_t size = strlen(from.data) + 1; 27 | data = new char[size]; 28 | memcpy(data, from.data, size); 29 | } 30 | }; 31 | 32 | string funReturningString() { 33 | string s("Foo"); 34 | return s; 35 | } 36 | 37 | int main() { 38 | 39 | string x("Bla"); 40 | 41 | string a(x); 42 | // we need a copy, program could look at x later 43 | string c(funReturningString()); 44 | // we *don't* need a copy, but still have to make one 45 | 46 | } 47 | -------------------------------------------------------------------------------- /01_values/01_07_advanced_string_move.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | /// Note: 7 | /// this is a very C-style example, to make the concept of move semantics and r-value references easier to understand 8 | /// you shouldn't actually write your own string class, and you really shouldn't do it like this 9 | 10 | struct string 11 | { 12 | char* data; 13 | 14 | string(const char* p) { 15 | size_t size = strlen(p) + 1; 16 | data = new char[size]; 17 | memcpy(data, p, size); 18 | } 19 | 20 | ~string() { 21 | if(data != nullptr) { 22 | delete[] data; 23 | } 24 | } 25 | 26 | string(const string& from) { 27 | std::cout << "Copying string" << std::endl; 28 | size_t size = strlen(from.data) + 1; 29 | data = new char[size]; 30 | memcpy(data, from.data, size); 31 | } 32 | 33 | string(string&& from) { 34 | std::cout << "Moving string" << std::endl; 35 | data = from.data; 36 | from.data = nullptr; 37 | } 38 | }; 39 | 40 | string funReturningString() { 41 | string s("Foo"); 42 | return s; 43 | } 44 | 45 | int main() { 46 | 47 | string x("Bla"); 48 | 49 | string a(x); 50 | // we need a copy, program could look at x later 51 | string c(funReturningString()); 52 | // we *don't* need a copy, and now we also don't create one! 53 | 54 | // if we know that we won't need some value any more, we can explicitly move it: 55 | string b(std::move(a)); 56 | // however, accessing the value later is an error! 57 | //std::cout << "a.data = " << a.data << std::endl; 58 | } 59 | -------------------------------------------------------------------------------- /01_values/01_values.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01_values", "01_values.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /01_values/01_values.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 24 | My01_values 25 | 10.0.15063.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | 79 | 80 | Console 81 | 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | true 88 | 89 | 90 | Console 91 | 92 | 93 | 94 | 95 | Level3 96 | MaxSpeed 97 | true 98 | true 99 | true 100 | 101 | 102 | true 103 | true 104 | Console 105 | 106 | 107 | 108 | 109 | Level3 110 | MaxSpeed 111 | true 112 | true 113 | true 114 | 115 | 116 | true 117 | true 118 | Console 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /02_classes_and_interfaces.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/02_classes_and_interfaces.pdf -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_01_basic_interfaces.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Some examples are taken (or minimally adapted) from the C++ Core Guidelines 3 | 4 | #include 5 | 6 | // PARAMETER TYPES //////////////////////////////////////////////////////////// 7 | 8 | /// Bad example: use global state to affect behavior 9 | 10 | bool g_round_up = false; 11 | 12 | int round_bad(double d) { 13 | return (int)((g_round_up) ? ceil(d) : d); // don't: "invisible" dependency 14 | } 15 | 16 | /// Better solution 17 | 18 | int round_better(double d, bool round_up) { 19 | return (int)((round_up) ? ceil(d) : d); 20 | } 21 | 22 | // PRECISELY TYPED //////////////////////////////////////////////////////////// 23 | 24 | /// Bad example: unclear semantics 25 | 26 | void sleep(double duration) { 27 | // What is "duration"? 28 | // If I call sleep(1.0) will it sleep for a second or a millisecond? 29 | // ... 30 | } 31 | 32 | /// Better solution: use specific type 33 | 34 | #include 35 | 36 | void sleep(std::chrono::milliseconds duration) { 37 | // Semantics are clear just from looking at the type 38 | // ... 39 | } 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | 43 | int main() { 44 | 45 | /// Note: in modern C++, more precisely typed interfaces 46 | /// does not necessarily mean that they are more cumbersome to use 47 | 48 | using namespace std::chrono_literals; 49 | 50 | sleep(33ms); 51 | 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_02_function_size.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::string; 4 | 5 | // FIRST EXAMPLE ////////////////////////////////////////////////////////////// 6 | 7 | // very bad: 8 | 9 | string searchAndReplace(string in, string toReplace, string replacement, 10 | bool ignoreCase, bool replaceAll, bool transformBackslash, bool isRegex); 11 | 12 | // one option - group parameters and make them descriptive at the call site: 13 | 14 | enum class ReplaceParameters { 15 | IGNORE_CASE = 0b0001, 16 | REPLACE_ALL = 0b0010, 17 | TRANSFORM_BACKSLASH = 0b0100, 18 | IS_REGEX = 0b1000, 19 | }; 20 | ReplaceParameters operator|(const ReplaceParameters& a, const ReplaceParameters& b) { 21 | return static_cast(static_cast(a) | static_cast(b)); 22 | } 23 | 24 | string searchAndReplace(string in, string toReplace, string replacement, ReplaceParameters params); 25 | // this is better in terms of self-documentation, but might end up with a large function 26 | 27 | // But we can do better: 28 | // 1) for some flags, a better option is often to create multiple functions 29 | // 2) we can implicitly encode some information in the type of the arguments and resolve it by overloading 30 | // 3) some functionality does not need to be part of the same single function 31 | 32 | struct Regex { 33 | Regex(string s) { } 34 | // ... 35 | }; 36 | 37 | struct StringIgnoringCase { 38 | StringIgnoringCase(string s) { } 39 | // ... 40 | }; 41 | 42 | string transformBackslashes(string in); 43 | 44 | string searchAndReplaceFirst(string in, string toReplace, string replacement); 45 | string searchAndReplaceFirst(string in, Regex toReplace, string replacement); 46 | string searchAndReplaceFirst(string in, StringIgnoringCase toReplace, string replacement); 47 | 48 | string searchAndReplaceAll(string in, string toReplace, string replacement); 49 | string searchAndReplaceAll(string in, Regex toReplace, string replacement); 50 | string searchAndReplaceAll(string in, StringIgnoringCase toReplace, string replacement); 51 | 52 | // NOTE: if these functions share all or part of their implementation, you 53 | // can and should do so internally without changing the interface 54 | 55 | // SECOND EXAMPLE ///////////////////////////////////////////////////////////// 56 | 57 | // bad: 58 | 59 | bool doRaysCollide(float x1, float y1, float z1, float dx1, float dy1, float dz1, 60 | float x2, float y2, float z2, float dx2, float dy2, float dz2) { 61 | // ... 62 | return false; 63 | } 64 | 65 | // better: 66 | 67 | struct Point { 68 | // ... 69 | }; 70 | 71 | bool doRaysCollide(Point start1, Point end1, Point start2, Point end2) { 72 | // ... 73 | return false; 74 | } 75 | 76 | // even better: 77 | 78 | struct Ray { 79 | Point origin; 80 | Point destination; 81 | // ... 82 | }; 83 | 84 | bool doRaysCollide(Ray a, Ray b) { 85 | // ... 86 | return false; 87 | } 88 | 89 | /////////////////////////////////////////////////////////////////////////////// 90 | 91 | int main() { 92 | 93 | // Terrible function design 94 | // -- no idea what this does just by looking at the invocation 95 | searchAndReplace("Hello World, hello universe", "hello", "Goodbye", 96 | true, true, false, false); 97 | 98 | // a bit better 99 | searchAndReplace("Hello World, hello universe", "hello", "Goodbye", 100 | ReplaceParameters::IGNORE_CASE | ReplaceParameters::REPLACE_ALL); 101 | 102 | // much better 103 | searchAndReplaceAll("Hello World, hello universe", StringIgnoringCase("hello"), "Goodbye"); 104 | 105 | return 0; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_03_parameters_and_retvals.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using std::string; 7 | 8 | /// PARAMETER TYPES /////////////////////////////////////////////////////////// 9 | 10 | string searchAndReplaceFirst(string in, string toReplace, string replacement); 11 | 12 | // strings might be larger and not cheap to copy 13 | // - move semantics help in some case, but not all 14 | 15 | /// *BAD* alternative: ///// 16 | 17 | string searchAndReplaceFirstBAD(string& in, string& toReplace, string& replacement); 18 | 19 | // no copies, but we might inadvertently change one of the input strings!! 20 | // also: whoever is using our interface will think that we want to change these strings 21 | // and: it doesn't even work for a common use case! (see below) 22 | 23 | /// Best choice: ///// 24 | 25 | string searchAndReplaceFirstBEST(const string& in, 26 | const string& toReplace, const string& replacement); 27 | 28 | // a *constant reference* allows us to avoid any overhead for copies, 29 | // but prevents changing the underlying object 30 | // Note: a constant lvalue reference can also bind to rvalues -- why? 31 | 32 | /// In-out parameters: ////// 33 | 34 | // what if we actually *do* want to change a parameter? 35 | 36 | void searchAndReplaceFirstInPlace(string& inout, const string& toReplace, const string& replacement); 37 | 38 | // this is the correct time to use a non-const reference 39 | 40 | ////////////////////////////////////////////////////////////////////////////// 41 | 42 | void usage() { 43 | searchAndReplaceFirstBAD("Bla", "a", "b"); 44 | 45 | searchAndReplaceFirstBEST("Bla", "a", "b"); 46 | } 47 | 48 | /// MULTIPLE RETURN VALUES /////////////////////////////////////////////////////////// 49 | 50 | // Example: min/max 51 | 52 | // Old/C-style 53 | 54 | void minmax_c(const std::vector& input, int& min, int& max) { 55 | min = std::numeric_limits::max(); 56 | max = std::numeric_limits::min(); 57 | for(auto& val : input) { 58 | if(val < min) min = val; 59 | if(val > max) max = val; 60 | } 61 | } 62 | 63 | // Multiple return values using pair 64 | 65 | std::pair minmax_p(const std::vector& input) { 66 | std::pair ret = { std::numeric_limits::max(), std::numeric_limits::min() }; 67 | for(auto& val : input) { 68 | if(val < ret.first) ret.first = val; 69 | if(val > ret.second) ret.second = val; 70 | } 71 | return ret; 72 | } 73 | 74 | // Multiple return values using struct 75 | 76 | struct Bounds { 77 | int min = std::numeric_limits::max(); 78 | int max = std::numeric_limits::min(); 79 | }; 80 | 81 | Bounds minmax_s(const std::vector& input) { 82 | Bounds ret; 83 | for(auto& val : input) { 84 | if(val < ret.min) ret.min = val; 85 | if(val > ret.max) ret.max = val; 86 | } 87 | return ret; 88 | } 89 | 90 | // Usage 91 | 92 | int main() { 93 | 94 | std::vector items { -4, 1, 22, -15, 50, 0, 3}; 95 | 96 | { // use minmax_c 97 | int min = 0, max = 0; 98 | minmax_c(items, min, max); 99 | std::cout << "minmax_c: " << min << " " << max << std::endl; 100 | } 101 | 102 | { // use minmax_p 103 | auto [min,max] = minmax_p(items); 104 | std::cout << "minmax_p: " << min << " " << max << std::endl; 105 | } 106 | 107 | { // use minmax_s 108 | auto [min,max] = minmax_s(items); 109 | std::cout << "minmax_s: " << min << " " << max << std::endl; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_04_return_smart_pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct ComplexNonMoveableThing { 5 | ComplexNonMoveableThing() { 6 | std::cout << "created ComplexNonMoveableThing #" << this << "." << std::endl; 7 | } 8 | ~ComplexNonMoveableThing() { 9 | std::cout << "destroyed ComplexNonMoveableThing #" << this << "." << std::endl; 10 | } 11 | ComplexNonMoveableThing(const ComplexNonMoveableThing& from) { 12 | std::cout << "copy constructed ComplexNonMoveableThing #" << this << " from #" << &from << "." << std::endl; 13 | } 14 | //ComplexNonMoveableThing(const ComplexNonMoveableThing& from) = delete; 15 | 16 | //ComplexNonMoveableThing(ComplexNonMoveableThing&&) = delete; 17 | }; 18 | 19 | /// What options do we have to return a "ComplexNonMoveableThing" ? 20 | 21 | /// 1; Best if not too expensive or impossible to copy 22 | ComplexNonMoveableThing createComplexNonMoveableThing1() { 23 | ComplexNonMoveableThing res; 24 | return res; 25 | } 26 | 27 | /// 2; "Classic" C++ 28 | // needs passing in at call site of pre-allocated structure 29 | // do NOT use in most cases 30 | void createComplexNonMoveableThing2(ComplexNonMoveableThing& output) { 31 | } 32 | 33 | /// 3; std::unique_ptr 34 | // best choice if a simple value does not work 35 | // lifetime is controlled by the unique_ptr's lifetime 36 | std::unique_ptr createComplexNonMoveableThing3() { 37 | return std::make_unique(); 38 | } 39 | 40 | /// 4; std::shared_ptr 41 | // *only* if you know that ownership for this will generally be shared 42 | // otherwise, use a unique_ptr 43 | std::shared_ptr createComplexNonMoveableThing4() { 44 | return std::make_shared(); 45 | } 46 | 47 | int main() { 48 | 49 | { 50 | std::cout << "i1 block" << std::endl; 51 | auto instance1 = createComplexNonMoveableThing1(); 52 | std::cout << "i1 block end" << std::endl; 53 | } 54 | 55 | std::cout << "------ 1" << std::endl; 56 | 57 | { 58 | std::cout << "i2 block" << std::endl; 59 | ComplexNonMoveableThing instance2; 60 | createComplexNonMoveableThing2(instance2); 61 | std::cout << "i2 block end" << std::endl; 62 | } 63 | 64 | std::cout << "------ 2" << std::endl; 65 | 66 | { 67 | std::cout << "i3 block" << std::endl; 68 | auto instance3 = createComplexNonMoveableThing3(); 69 | std::cout << "i3 block end" << std::endl; 70 | } 71 | 72 | std::cout << "------ 3" << std::endl; 73 | 74 | { 75 | std::cout << "i4 block" << std::endl; 76 | auto instance4 = createComplexNonMoveableThing4(); 77 | std::cout << "i4 block end" << std::endl; 78 | } 79 | 80 | std::cout << "------ 4" << std::endl; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_05_class_hierarchies.cpp: -------------------------------------------------------------------------------- 1 | 2 | /// Textbook example 3 | 4 | struct Vec2D { 5 | double x, y; 6 | Vec2D(double x, double y) : x(x), y(y) {} 7 | }; 8 | 9 | class Shape { 10 | public: 11 | virtual double area() const = 0; 12 | virtual double circumference() const = 0; 13 | 14 | virtual void move(const Vec2D& v) = 0; 15 | }; 16 | // Notes: 17 | // - "virtual" to signify virtual member functions 18 | // (called depending on run-time type) 19 | // - "const" after member function to indicate that 20 | // it does not change the object state (IMPORTANT) 21 | // - " = 0" on a virtual member function means that it is *pure virtual* 22 | // -> must be implemented in derived in order for it to be complete 23 | 24 | class Circle : public Shape { 25 | Vec2D center; 26 | double radius; 27 | 28 | public: 29 | Circle(Vec2D center, double radius) 30 | : center(center) 31 | , radius(radius) {} 32 | 33 | double area() const override { /* ... */ } 34 | double circumference() const override { /* ... */ } 35 | 36 | void move(const Vec2D& v) override { /* ... */ } 37 | }; 38 | // Notes: 39 | // - ": public Shape" means public inheritance from Shape 40 | // -> if members are publicly visible in Shape, they are also publicly visible in Circle 41 | // - use the "override" keyword to indicate that 42 | // you want to override a base implementation (IMPORTANT) 43 | 44 | class Rectangle : public Shape { 45 | Vec2D bottomLeft; 46 | Vec2D extents; 47 | 48 | public: 49 | Rectangle(Vec2D bottomLeft, Vec2D extents) 50 | : bottomLeft(bottomLeft) 51 | , extents(extents) {} 52 | 53 | double area() const override { /* ... */ } 54 | double circumference() const override { /* ... */ } 55 | 56 | void move(const Vec2D& v) override { /* ... */ } 57 | }; 58 | 59 | class Square : public Rectangle { 60 | public: 61 | Square(Vec2D bottomLeft, double sideLength) 62 | : Rectangle(bottomLeft, Vec2D(sideLength, sideLength)) {} 63 | }; 64 | // Notes: 65 | // we are inheriting the *implementation* of "area", 66 | // "circumference" and "move" 67 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_06_multiple_inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Collider { }; 4 | 5 | class Sprite { }; 6 | 7 | class AnimatedSprite : public Sprite { 8 | public: 9 | void advanceTime(double deltaT) { 10 | /* ... */ 11 | } 12 | }; 13 | 14 | class SoundEmitter { }; 15 | 16 | class Controlled { }; 17 | 18 | class AIRoutine { }; 19 | 20 | class Pickup : public AnimatedSprite, public SoundEmitter { }; 21 | 22 | class Wall : public Collider, public Sprite { }; 23 | 24 | class Lifeform : public Collider, public AnimatedSprite, public SoundEmitter { }; 25 | 26 | class Player : public Lifeform, public Controlled { }; 27 | 28 | class Enemy : public Lifeform, public AIRoutine { }; 29 | 30 | // Notes: 31 | // Multiple inheritance can be useful, especially for interfaces. 32 | // For implementation, *think about whether composition could solve the same problem* 33 | 34 | // Advantage of multiple inheritance: can be used to store all types conforming to one interface in containers 35 | void resolveCollisions(std::vector colliders) { 36 | /* ... */ 37 | } 38 | 39 | void advanceTime(double deltaT, std::vector sprites) { 40 | for(auto sprite : sprites) { 41 | sprite->advanceTime(deltaT); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_07_virtual_inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | int i[32]; 5 | }; 6 | 7 | class B : public A { }; 8 | class C : public A { }; 9 | class D : public B, public C { }; 10 | 11 | void nonVirtualInheritance() { 12 | std::cout << "sizeof(A): " << sizeof(A) << std::endl; 13 | std::cout << "sizeof(B): " << sizeof(B) << std::endl; 14 | std::cout << "sizeof(C): " << sizeof(C) << std::endl; 15 | std::cout << "sizeof(D): " << sizeof(D) << std::endl; 16 | // Note: D clearly contains two instances of A! 17 | D d; 18 | D* dp = &d; 19 | B* dpb = dp; 20 | C* dpc = dp; 21 | // A* dpa = dp; 22 | // Note: the line above is ambiguous! 23 | } 24 | 25 | class Bv : virtual public A { }; 26 | class Cv : virtual public A { }; 27 | class Dv : public Bv, public Cv { }; 28 | 29 | void virtualInheritance() { 30 | std::cout << "sizeof(A): " << sizeof(A) << std::endl; 31 | std::cout << "sizeof(Bv): " << sizeof(Bv) << std::endl; 32 | std::cout << "sizeof(Cv): " << sizeof(Cv) << std::endl; 33 | std::cout << "sizeof(Dv): " << sizeof(Dv) << std::endl; 34 | // Note: a bit of extra memory (usually 1 pointer) 35 | // in Bv and Cv for virtual inheritance, but no duplication 36 | Dv d; 37 | Dv* dp = &d; 38 | Bv* dpb = dp; 39 | Cv* dpc = dp; 40 | A* dpa = dp; 41 | // Note: the line above is no longer ambiguous! 42 | } 43 | 44 | int main() { 45 | nonVirtualInheritance(); 46 | std::cout << "===" << std::endl; 47 | virtualInheritance(); 48 | } 49 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_08_private_inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class WriteOnlyMemory : private std::vector { 5 | using base = std::vector; 6 | public: 7 | using base::push_back; 8 | using base::emplace_back; 9 | using base::size; 10 | }; 11 | 12 | namespace name { 13 | void foo(int i) { } 14 | } 15 | 16 | using namespace name; 17 | 18 | int main() { 19 | 20 | foo(2); 21 | 22 | WriteOnlyMemory wom; 23 | 24 | wom.push_back(1.0); 25 | wom.emplace_back(2.0); 26 | 27 | std::cout << wom.size() << std::endl; 28 | 29 | // prevents access: 30 | //wom.at(0); 31 | } 32 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_09_operator_overloading.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace bla { 5 | 6 | struct Vec2D { 7 | 8 | double x, y; 9 | 10 | Vec2D(double x, double y) : x(x), y(y) {} 11 | 12 | Vec2D operator+(Vec2D other) const { 13 | return { x + other.x, y + other.y }; 14 | } 15 | 16 | Vec2D operator*(double factor) const { 17 | return { x*factor, y*factor }; 18 | } 19 | }; 20 | 21 | std::ostream& operator<<(std::ostream& stream, Vec2D v) { 22 | return stream << "( " << std::setw(8) << v.x << " , " << std::setw(8) << v.y << " )"; 23 | } 24 | 25 | void basicOps() { 26 | Vec2D a{ 1.0, 5.0 }; 27 | 28 | std::cout << "a : " << a << std::endl; 29 | std::cout << "a+a : " << a + a << std::endl; 30 | std::cout << "a*0.5 : " << a*0.5 << std::endl; 31 | 32 | //std::cout << "0.5*a : " << 0.5*a << std::endl; 33 | // Note: above doesn't work! 34 | } 35 | 36 | Vec2D operator*(double factor, Vec2D vec) { 37 | return vec*factor; 38 | } 39 | 40 | void doSomethingWith(Vec2D v) {} 41 | 42 | void doSomethingWithout() {} 43 | 44 | } // end namespace 45 | 46 | void standaloneOps() { 47 | // note: we need to use the namespace qualification here 48 | bla::Vec2D b{ 3.0, 2.0 }; 49 | // ... and here 50 | bla::doSomethingWithout(); 51 | // but not here! argument-dependent lookup 52 | doSomethingWith(b); 53 | 54 | std::cout << "b : " << b << std::endl; 55 | std::cout << "0.5*b : " << 0.5*b << std::endl; 56 | // Now it works 57 | } 58 | 59 | int main() { 60 | bla::basicOps(); 61 | //standaloneOps(); 62 | } 63 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_10_friends.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class F; 5 | 6 | class Secret { 7 | std::string name; 8 | double weight; 9 | 10 | friend F; 11 | 12 | public: 13 | Secret(std::string name, double weight) 14 | : name(name) 15 | , weight(weight) {} 16 | }; 17 | 18 | class F { 19 | public: 20 | void leakInformation(Secret s) { 21 | std::cout << s.name << ": " << s.weight << std::endl; 22 | } 23 | }; 24 | 25 | int main() { 26 | 27 | Secret s{ "Peter", 60.0 }; 28 | 29 | //std::cout << s.name << ": " << s.weight << std::endl; 30 | // Note: above does not compile 31 | 32 | F leaker; 33 | leaker.leakInformation(s); 34 | } 35 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_11_hidden_friends.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Bounds { 5 | public: 6 | Bounds(int min, int max) 7 | : min(min) 8 | , max(max) {} 9 | 10 | private: 11 | int min, max; 12 | 13 | friend std::ostream& operator<<(std::ostream& os, const Bounds& b); 14 | }; 15 | 16 | std::ostream& operator<<(std::ostream& os, const Bounds& b) { 17 | return os << "[" << b.min << "," << b.max << "]"; 18 | } 19 | 20 | class BoundsHidden { 21 | public: 22 | BoundsHidden(int min, int max) : min(min), max(max) {} 23 | 24 | private: 25 | int min, max; 26 | 27 | friend std::ostream& operator<<(std::ostream& os, const BoundsHidden& b) { 28 | return os << "[" << b.min << "," << b.max << "]"; 29 | } 30 | }; 31 | 32 | class Foo { 33 | }; 34 | 35 | int main() { 36 | Bounds b{1,5}; 37 | std::cout << b << std::endl; 38 | 39 | BoundsHidden bh{2,6}; 40 | std::cout << bh << std::endl; 41 | 42 | //Foo f; 43 | //std::cout << f << std::endl; 44 | } 45 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_classes_and_interfaces.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02_classes_and_interfaces", "02_classes_and_interfaces.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /02_classes_and_interfaces/02_classes_and_interfaces.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 24 | My02_classes_and_interfaces 25 | 10.0.15063.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | 79 | 80 | Console 81 | 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | true 88 | 89 | 90 | Console 91 | 92 | 93 | 94 | 95 | Level3 96 | MaxSpeed 97 | true 98 | true 99 | true 100 | 101 | 102 | true 103 | true 104 | Console 105 | 106 | 107 | 108 | 109 | Level3 110 | MaxSpeed 111 | true 112 | true 113 | true 114 | 115 | 116 | true 117 | true 118 | Console 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/03_lambdas_and_algorithms.pdf -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_01_containers_sequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct Traced { 10 | Traced() { std::cout << "Traced #" << this << " constructed.\n"; } 11 | ~Traced() { std::cout << "Traced #" << this << " destroyed.\n"; } 12 | Traced(const Traced& other) { std::cout << "Traced #" << this << " copy constructed from " << &other << ".\n"; } 13 | Traced(Traced&& other) noexcept { std::cout << "Traced #" << this << " move constructed from " << &other << ".\n"; } 14 | Traced& operator=(const Traced& other) { std::cout << "Traced #" << this << " copy assigned to from " << &other << ".\n"; return *this; } 15 | Traced& operator=(Traced&& other) noexcept { std::cout << "Traced #" << this << " move assigned to from " << &other << ".\n"; return *this; } 16 | }; 17 | 18 | void array_test() { 19 | 20 | // array of 10 "double" values 21 | std::array double_values{ 0.0 }; 22 | // note that "10" needs to be a compile-time constant value 23 | 24 | // array of 3 "Traced" values 25 | std::cout << "1 ---- Before traced_array" << std::endl; 26 | std::array traced_array; 27 | std::cout << "2 ---- Before auto traced_copy = traced_array" << std::endl; 28 | auto traced_copy = traced_array; 29 | std::cout << "3 ---- Before traced_copy = traced_array" << std::endl; 30 | traced_copy = traced_array; 31 | std::cout << "4 ---- Before end of array_test" << std::endl; 32 | 33 | // note the value semantics, unlike C-style arrays! 34 | } 35 | 36 | void vector_test() { 37 | 38 | std::cout << "0 ---- Before traced_vector" << std::endl; 39 | std::vector traced_vector; 40 | std::cout << "1 ---- Before traced_vector.reserve(2)" << std::endl; 41 | traced_vector.reserve(2); 42 | std::cout << "2 ---- Before traced_vector.push_back" << std::endl; 43 | traced_vector.push_back(Traced()); 44 | std::cout << "3 ---- Before traced_vector.emplace_back" << std::endl; 45 | traced_vector.emplace_back(); 46 | std::cout << "4 ---- Before traced_vector.emplace_back (3rd element)" << std::endl; 47 | traced_vector.emplace_back(); 48 | std::cout << "5 ---- Before end of vector_test" << std::endl; 49 | 50 | // note that having to resize the vector implies copying (or moving) all existing elements! 51 | } 52 | 53 | void various_list_test() { 54 | std::deque traced_deque; 55 | // a double-ended queue with indexed access 56 | // e.g. traced_deque[0] is possible (though invalid since the deque is empty) 57 | 58 | std::list traced_list; 59 | // a doubly linked list (no indexed access) 60 | 61 | std::forward_list traced_forward_list; 62 | // a single-linked-list (no indexed access) 63 | // more space-efficient than the above, useful if bidirectional iteration is not required 64 | } 65 | 66 | 67 | int main() { 68 | //array_test(); 69 | vector_test(); 70 | } 71 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_02_containers_associative.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | struct Basic { 7 | }; 8 | 9 | void set_test_fail() { 10 | std::set basic_set; 11 | // note: this compiles (!) 12 | 13 | //basic_set.insert(Basic()); 14 | // note: here we encounter our first real C++ template error 15 | // let's talk about what goes wrong here for a quarter of an hour 16 | } 17 | 18 | 19 | struct ComparableBasic { 20 | int val; 21 | }; 22 | bool operator<(ComparableBasic a, ComparableBasic b) noexcept { 23 | return a.val < b.val; 24 | } 25 | 26 | void set_test() { 27 | std::set comp_set; 28 | 29 | comp_set.insert({ 19 }); 30 | comp_set.insert({ 5 }); 31 | comp_set.insert({ 7 }); 32 | comp_set.insert({ 5 }); 33 | 34 | for(auto cb : comp_set) { 35 | std::cout << cb.val << std::endl; 36 | } 37 | } 38 | 39 | 40 | void map_test() { 41 | std::map test_map; 42 | 43 | test_map[{5}] = 5.0; 44 | test_map[{42}] = 1.0; 45 | test_map[{5}] = 7.0; 46 | 47 | for(auto entry : test_map) { 48 | std::cout << entry.first.val << " : " << entry.second << std::endl; 49 | } 50 | std::cout << std::endl; 51 | 52 | // C++17 Structured Binding 53 | for(auto [k, v] : test_map) { 54 | std::cout << k.val << " : " << v << std::endl; 55 | } 56 | } 57 | 58 | 59 | int main() { 60 | //set_test(); 61 | map_test(); 62 | } 63 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_03_containers_unordered.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | struct Basic { 6 | }; 7 | 8 | void unordered_set_test_fail() { 9 | //std::unordered_set basic_set; 10 | //basic_set.insert(Basic()); 11 | // note: here we encounter our second real C++ template error 12 | // let's see if we can do it in 5 minutes now 13 | } 14 | 15 | 16 | struct BasicHashable { 17 | int val; 18 | }; 19 | 20 | bool operator==(BasicHashable a, BasicHashable b) { 21 | return a.val == b.val; 22 | } 23 | 24 | namespace std 25 | { 26 | template<> struct hash 27 | { 28 | size_t operator()(const BasicHashable& s) const noexcept { 29 | return std::hash{}(s.val); 30 | } 31 | }; 32 | } 33 | 34 | void unordered_set_test() { 35 | std::unordered_set basic_hashable_set; 36 | 37 | basic_hashable_set.insert({ 8 }); 38 | basic_hashable_set.insert({ 5 }); 39 | basic_hashable_set.insert({ 42 }); 40 | basic_hashable_set.insert({ 6 }); 41 | basic_hashable_set.insert({ 7 }); 42 | basic_hashable_set.insert({ 5 }); 43 | 44 | for(auto cb : basic_hashable_set) { 45 | std::cout << cb.val << std::endl; 46 | } 47 | } 48 | 49 | 50 | int main() { 51 | unordered_set_test(); 52 | } 53 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_04_iterators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | std::vector vec{ 0,1,2,3,41,42 }; 8 | 9 | // note: std::vector offers a contiguous iterator 10 | std::cout << *vec.begin() << std::endl; 11 | std::cout << *vec.rbegin() << std::endl; 12 | std::cout << *(vec.begin() + 2) << std::endl; 13 | std::cout << *(vec.rbegin() + 1) << std::endl; 14 | std::cout << "----" << std::endl; 15 | 16 | // when we are only reading, we should use the constant (c*) versions 17 | std::cout << *vec.cbegin() << std::endl; 18 | std::cout << *vec.crbegin() << std::endl; 19 | std::cout << *(vec.cbegin() + 2) << std::endl; 20 | std::cout << *(vec.crbegin() + 1) << std::endl; 21 | std::cout << "----" << std::endl; 22 | 23 | // we can apply std::distance, and in this case it will be of constant complexity 24 | std::cout << "dist: " << std::distance(vec.begin() + 2, vec.end()) << std::endl; 25 | std::cout << "----" << std::endl; 26 | 27 | // std::back_inserter is an iterator adapter 28 | auto inserter = std::back_inserter(vec); 29 | *inserter++ = 55; 30 | *inserter++ = 56; 31 | 32 | for(int v : vec) { 33 | std::cout << v << ", "; 34 | } 35 | std::cout << std::endl; 36 | 37 | for(auto it = std::make_reverse_iterator(vec.cend()); it != std::make_reverse_iterator(vec.cbegin()); it++) { 38 | std::cout << *it << ", "; 39 | } 40 | std::cout << std::endl; 41 | 42 | // there is a shorthand for that: vec.crend() / vec.crbegin(); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_05_lambda_basics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void apply_to_all(std::vector& vec, std::function fun) { 6 | for(auto& element : vec) { 7 | element = fun(element); 8 | } 9 | } 10 | 11 | int main(int argc, char** argv) { 12 | 13 | auto add = [](int a, int b) { 14 | return a + b; 15 | }; 16 | int sum = add(5, 6); 17 | 18 | auto mul = [](int a, int b) -> int { 19 | return a * b; 20 | }; 21 | /// Note: " -> int" explicitly defines the return type of the lambda 22 | /// it is only necessary if there are multiple "return" statements without a unique return type 23 | 24 | std::vector values { 1.0, 2.0, 4.0, 8.0 }; 25 | 26 | apply_to_all(values, [](double value) { 27 | return value*value; 28 | }); 29 | 30 | for(auto v : values) { 31 | std::cout << v << ", "; 32 | } 33 | std::cout << std::endl; 34 | } 35 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_06_lambda_captures.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool true_for_any(const std::vector& vec, std::function condition) { 8 | for(auto v : vec) { 9 | if(condition(v)) return true; 10 | } 11 | return false; 12 | } 13 | 14 | bool has_value_between(const std::vector& vec, double lower_bound, double upper_bound) { 15 | return true_for_any(vec, [lower_bound, upper_bound](double val) { 16 | return val >= lower_bound && val <= upper_bound; 17 | }); 18 | // captures "lower_bound" and "upper_bound" by value (i.e. creates a copy) 19 | /// equivalent: 20 | //return true_for_any(vec, [=](double val) { 21 | // return val >= lower_bound && val <= upper_bound; 22 | //}); 23 | /// note: 24 | // [=] : default capture by value 25 | // [&] : default capture by reference 26 | } 27 | 28 | struct FullName { 29 | const std::string first; 30 | const std::string last; 31 | 32 | FullName(std::string first, std::string last) 33 | : first(first) 34 | , last(last) 35 | {} 36 | 37 | bool containsAnyName(std::vector s) { 38 | //return std::any_of(s.cbegin(), s.cend(), [&](const std::string& str) { 39 | // return first == str || last == str; 40 | //}); 41 | // [&] captures "this" by reference (or rather, the pointer by value) 42 | 43 | /// the following does not work: (cannot capture members directly) 44 | //return std::any_of(s.cbegin(), s.cend(), [first, last](const std::string& str) { 45 | // return first == str || last == str; 46 | //}); 47 | 48 | /// this works -- captures the two relevant members by copy 49 | //return std::any_of(s.cbegin(), s.cend(), [f = first, l = last](const std::string& str) { 50 | // return f == str || l == str; 51 | //}); 52 | 53 | /// equivalent to the first option, but more explicit (still captures this by reference) 54 | //return std::any_of(s.cbegin(), s.cend(), [this](const std::string& str) { 55 | // return first == str || last == str; 56 | //}); 57 | 58 | /// by-copy capture of the current object 59 | //return std::any_of(s.cbegin(), s.cend(), [*this](const std::string& str) { 60 | // return first == str || last == str; 61 | //}); 62 | } 63 | }; 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_07_lambda_implementation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void test1() { 4 | 5 | int a = 5; 6 | 7 | // lambda version: 8 | 9 | { 10 | auto x = [a](int i) { return a*i; }; 11 | std::cout << x(4) << std::endl; 12 | } 13 | 14 | // fully written out: 15 | 16 | { 17 | struct Unnamed1 { 18 | // captured by value -> field in struct 19 | int a; 20 | 21 | // NO DEFAULT CONSTRUCTOR 22 | 23 | // default copy / move semantics 24 | Unnamed1(const Unnamed1&) = default; 25 | Unnamed1(Unnamed1&&) = default; 26 | 27 | // not assignable 28 | Unnamed1& operator=(const Unnamed1&) = delete; 29 | Unnamed1& operator=(const Unnamed1&&) = delete; 30 | 31 | // default destructor 32 | ~Unnamed1() = default; 33 | 34 | // Call operator constructed from the lambda expression 35 | // operator is "const" because no "mutable" was specified for the lambda 36 | constexpr int operator()(int i) const { 37 | return a*i; 38 | } 39 | }; 40 | 41 | auto x = Unnamed1{ a }; 42 | std::cout << x(4) << std::endl; 43 | } 44 | } 45 | 46 | 47 | void test2() { 48 | 49 | int a = 5; 50 | float b = 5.0f; 51 | double c = 0.5f; 52 | 53 | // lambda version: 54 | 55 | { 56 | auto x = [a,&b,c](int i, const int& j) mutable noexcept { 57 | b *= (float)c; 58 | return a*i*j; 59 | }; 60 | std::cout << x(4, 5) << std::endl; 61 | std::cout << b << std::endl; 62 | } 63 | 64 | // fully written out: 65 | 66 | { 67 | struct Unnamed { 68 | // captured by value -> field in struct 69 | int a; 70 | float& b; // OPTIONAL 71 | double c; 72 | 73 | // NO DEFAULT CONSTRUCTOR 74 | 75 | Unnamed(const Unnamed&) = default; 76 | Unnamed(Unnamed&&) = default; 77 | Unnamed& operator=(const Unnamed&) = delete; 78 | Unnamed& operator=(const Unnamed&&) = delete; 79 | ~Unnamed() = default; 80 | 81 | // Call operator constructed from the lambda expression 82 | // operator is not "const" because of "mutable" 83 | // operator is "noexcept" as it was declared in the lambda expression 84 | constexpr int operator()(int i, const int& j) noexcept { 85 | b *= (float)c; 86 | return a*i*j; 87 | } 88 | }; 89 | 90 | auto x = Unnamed{ a, b, c }; 91 | std::cout << x(4, 5) << std::endl; 92 | std::cout << b << std::endl; 93 | } 94 | } 95 | 96 | using fun_ptr_type = int(*)(int, int); 97 | 98 | void test3() { 99 | 100 | // lambda version: 101 | 102 | { 103 | auto x = [](int i, int j) constexpr { 104 | return i*j; 105 | }; 106 | std::cout << x(4, 5) << std::endl; 107 | int arr[x(1, 2)]; 108 | fun_ptr_type fun = x; 109 | 110 | } 111 | 112 | // fully written out: 113 | 114 | { 115 | struct Unnamed { 116 | // NO DEFAULT CONSTRUCTOR 117 | 118 | Unnamed(const Unnamed&) = default; 119 | Unnamed(Unnamed&&) = default; 120 | Unnamed& operator=(const Unnamed&) = delete; 121 | Unnamed& operator=(const Unnamed&&) = delete; 122 | ~Unnamed() = default; 123 | 124 | operator fun_ptr_type() const { 125 | /* compiler defined */ 126 | return (fun_ptr_type)0; /// NOTE: this is just to get it to compile, will crash 127 | } 128 | 129 | // Call operator constructed from the lambda expression 130 | // operator is "constexpr" as specified 131 | // note that as of C++17, the examples in test1 and test2 are also autoamtically "constexpr" 132 | constexpr int operator()(int i, int j) { 133 | return i*j; 134 | } 135 | }; 136 | 137 | auto x = Unnamed{}; 138 | std::cout << x(4, 5) << std::endl; 139 | int arr[x(1, 2)]; 140 | fun_ptr_type fun = x; 141 | } 142 | } 143 | 144 | 145 | int main(int argc, char **argv) { 146 | test2(); 147 | } 148 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_08_alg_examples.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool has_duplicates(std::vector v) { 6 | std::sort(v.begin(), v.end()); 7 | return std::adjacent_find(v.begin(), v.end()) != v.end(); 8 | } 9 | 10 | bool has_elements_closer_than(std::vector v, int range) { 11 | std::sort(v.begin(), v.end()); 12 | return std::adjacent_find(v.begin(), v.end(), [range](int l, int r) { 13 | return abs(l - r) < range; 14 | }) != v.end(); 15 | } 16 | 17 | std::vector select_even(const std::vector& v) { 18 | std::vector ret; 19 | std::copy_if(v.cbegin(), v.cend(), std::back_inserter(ret), [](int num) { 20 | return num % 2 == 0; 21 | }); 22 | return ret; 23 | } 24 | 25 | 26 | int main(int argc, char** argv) { 27 | 28 | { 29 | std::vector v1{ 1,2,3,42,5 }; 30 | std::cout << "has_duplicates(v1) : " << has_duplicates(v1) << std::endl; 31 | } 32 | { 33 | std::vector v2{ 1,2,3,42,5,2 }; 34 | std::cout << "has_duplicates(v2) : " << has_duplicates(v2) << std::endl; 35 | } 36 | 37 | { 38 | std::vector v1{ 1,2,3,42,5 }; 39 | std::cout << "has_elements_closer_than(v1, 2) : " << has_elements_closer_than(v1, 2) << std::endl; 40 | } 41 | { 42 | std::vector v3{ 42,1,20,30,50 }; 43 | std::cout << "has_elements_closer_than(v3, 2) : " << has_elements_closer_than(v3, 2) << std::endl; 44 | std::cout << "has_elements_closer_than(v3, 9) : " << has_elements_closer_than(v3, 9) << std::endl; 45 | } 46 | 47 | { 48 | std::vector v1{ 1,2,3,42,5 }; 49 | auto even = select_even(v1); 50 | std::cout << "select_even(v1) : "; 51 | for(auto i : even) { std::cout << i << ", "; } 52 | std::cout << std::endl; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_09_exec_policy_bench.cpp: -------------------------------------------------------------------------------- 1 | // g++ main.cpp -O3 -std=c++20 -ltbb -Wall -Wextra -o main 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | constexpr int REPS = 10; 13 | using bench_type = double; 14 | 15 | template 16 | void test_exec_policy(bool dry, std::string name, E exec, std::vector& a, std::vector& b) { 17 | using namespace std::chrono_literals; 18 | 19 | auto start = std::chrono::high_resolution_clock::now(); 20 | for (int i = 0; i < REPS; ++i) { 21 | std::transform(exec, a.cbegin(), a.cend(), b.begin(), [](double x) { return x / (x + std::sin(x)); }); 22 | std::transform(exec, b.cbegin(), b.cend(), a.begin(), [](double x) { return x * (x + std::cos(x)); }); 23 | } 24 | auto end = std::chrono::high_resolution_clock::now(); 25 | double elapsed = (end - start) / 1.0ms; 26 | if (!dry) { 27 | std::cout << std::setw(24) << name << " : " << std::fixed << std::setprecision(2) << std::setw(10) 28 | << elapsed / (REPS*2) << " ms\n"; 29 | } 30 | else { 31 | std::cout << "." << std::flush; 32 | } 33 | } 34 | 35 | int main(int argc, char** argv) { 36 | 37 | size_t n = 10000000; 38 | if(argc>1) n = std::atol(argv[1]); 39 | 40 | std::vector a(n); 41 | std::vector b(n); 42 | 43 | std::iota(a.begin(), a.end(), 1.0); 44 | 45 | bool dry = true; 46 | 47 | auto run_benches = [&dry, &a, &b] { 48 | test_exec_policy(dry, "seq", std::execution::seq, a, b); 49 | test_exec_policy(dry, "unseq", std::execution::unseq, a, b); 50 | test_exec_policy(dry, "par", std::execution::par, a, b); 51 | test_exec_policy(dry, "par_unseq", std::execution::par_unseq, a, b); 52 | }; 53 | 54 | run_benches(); 55 | std::cout << std::endl; 56 | dry = false; 57 | run_benches(); 58 | } 59 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_lambdas_and_algorithms.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03_lambdas_and_algorithms", "03_lambdas_and_algorithms.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /03_lambdas_and_algorithms/03_lambdas_and_algorithms.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0.15063.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v141 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v141 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v141 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v141 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | true 81 | stdcpplatest 82 | 83 | 84 | Console 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | stdcpplatest 93 | 94 | 95 | Console 96 | 97 | 98 | 99 | 100 | Level3 101 | MaxSpeed 102 | true 103 | true 104 | true 105 | stdcpplatest 106 | 107 | 108 | true 109 | true 110 | Console 111 | 112 | 113 | 114 | 115 | Level3 116 | MaxSpeed 117 | true 118 | true 119 | true 120 | stdcpplatest 121 | 122 | 123 | true 124 | true 125 | Console 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /04_templates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/04_templates.pdf -------------------------------------------------------------------------------- /04_templates/04_01_function_templates_basic.cpp: -------------------------------------------------------------------------------- 1 | 2 | #if true 3 | 4 | int abs(int x) { 5 | return x > 0 ? x : -x; 6 | } 7 | 8 | float abs(float x) { 9 | return x > 0 ? x : -x; 10 | } 11 | 12 | double abs(double x) { 13 | return x > 0 ? x : -x; 14 | } 15 | 16 | char abs(char x) { 17 | return x > 0 ? x : -x; 18 | } 19 | 20 | // ... 21 | 22 | #else 23 | 24 | template 25 | T abs(T x) { 26 | return x > 0 ? x : -x; 27 | } 28 | 29 | #endif 30 | 31 | int main() { 32 | int x = -7; 33 | x = abs(x); 34 | double y = -12.5; 35 | y = abs(y); 36 | float z = -0.25; 37 | z = abs(z); 38 | } 39 | -------------------------------------------------------------------------------- /04_templates/04_02_template_parameter_categories.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | // Non-type template parameters 10 | 11 | template 12 | double get_element(std::array arr) { 13 | static_assert(I >= 0 && I < N, "Array access out of bounds"); 14 | return arr[I]; 15 | } 16 | 17 | 18 | 19 | // Type template parameters 20 | 21 | template 22 | P apply_function(P input, F function) { 23 | return function(input); 24 | } 25 | 26 | 27 | 28 | // Template template parameters 29 | 30 | template class TT, typename T, typename A> 31 | void output(const TT& container) { 32 | for(auto& element : container) { 33 | std::cout << element << ", "; 34 | } 35 | std::cout << std::endl; 36 | } 37 | 38 | 39 | 40 | int main() { 41 | { 42 | std::array arr{ {0} }; 43 | get_element<7>(arr); 44 | 45 | //get_element<-1>(arr); 46 | //get_element<17>(arr); 47 | } 48 | std::cout << "---" << std::endl; 49 | { 50 | int x = 5; 51 | int result = apply_function(x, [](int v) { return v * 2; }); 52 | std::cout << x << " -> " << result << std::endl; 53 | } 54 | { 55 | std::string x = "Hello"; 56 | std::string result = apply_function(x, [](std::string v) { return v + " world"; }); 57 | std::cout << x << " -> " << result << std::endl; 58 | } 59 | std::cout << "---" << std::endl; 60 | { 61 | std::vector v1{ 1,2,3,4 }; 62 | output(v1); 63 | } 64 | { 65 | std::list v2{ "Bla", "Alb", "Xyz"}; 66 | output(v2); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /04_templates/04_03_template_parameter_packs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | // ---------------------------------------------- template type parameter pack 6 | 7 | #if true 8 | 9 | template 10 | T sum(T last) { 11 | return last; 12 | } 13 | 14 | template 15 | T sum(T t, Rest... rest) { 16 | return t + sum(rest...); 17 | } 18 | 19 | #else 20 | 21 | // C++17 fold expression: 22 | 23 | template 24 | T sum(T t, Rest... rest) { 25 | return (t + ... + rest); 26 | } 27 | 28 | #endif 29 | 30 | // ---------------------------------------------- template template parameter pack 31 | // ... left as an exercise 32 | 33 | 34 | int main() { 35 | { 36 | std::cout << "sum(1, 2, 3, 10) : " << sum(1, 2, 3, 10) << std::endl; 37 | std::cout << "sum(1.0, 0.4, 0.1) : " << sum(1.0, 0.4, 0.1) << std::endl; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /04_templates/04_04_template_arguments.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | T abs(T x) { 7 | return x > 0 ? x : -x; 8 | } 9 | 10 | template 11 | T num_cast(In v) { 12 | return (T)v; 13 | } 14 | 15 | template class ListTT = std::vector> 16 | ListTT> create_sequence(int a, int b, int c) { 17 | return { a, b, c }; 18 | } 19 | 20 | int main() { 21 | abs(5); // argument type implicitly deduced as "int" from calling context 22 | abs(5); // template argument explicitly specified as double 23 | 24 | int x = 0; 25 | double y = num_cast(x); 26 | float z = num_cast(y); 27 | // first template argument for num_cast needs to be explicit; 28 | // cannot be deduced from the function arguments at the call site 29 | 30 | auto vec = create_sequence(1, 2, 3); 31 | // "vec" is a "std::vector" due to the 32 | // defaulted template template parameter 33 | auto list = create_sequence(2, 3, 4); 34 | // "list" is a "std::list" 35 | 36 | } 37 | -------------------------------------------------------------------------------- /04_templates/04_05_class_template_basics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class Vector { 6 | ScalarType contents[Length] = {}; 7 | 8 | public: 9 | Vector() {} 10 | Vector(std::initializer_list init) 11 | { 12 | std::copy(init.begin(), init.end(), contents); 13 | } 14 | 15 | ScalarType operator[](int idx) const { 16 | return contents[idx]; 17 | } 18 | ScalarType& operator[](int idx) { 19 | return contents[idx]; 20 | } 21 | 22 | Vector operator+(const Vector& other) const { 23 | Vector ret; 24 | for(int i = 0; i < Length; ++i) { 25 | ret[i] = contents[i] + other[i]; 26 | } 27 | return ret; 28 | } 29 | }; 30 | 31 | using Vec3D = Vector; 32 | 33 | int main(int argc, char** argv) { 34 | 35 | Vec3D zero; 36 | Vec3D one{ 1.0, 1.0, 1.0 }; 37 | 38 | zero + one; 39 | } 40 | -------------------------------------------------------------------------------- /04_templates/04_06_template_specialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class Vector { 6 | ScalarType contents[Length]; 7 | 8 | public: 9 | Vector() 10 | { 11 | for(int i = 0; i < Length; ++i) contents[i] = 0; 12 | } 13 | Vector(std::initializer_list init) 14 | { 15 | std::copy(init.begin(), init.end(), contents); 16 | } 17 | 18 | ScalarType operator[](int idx) const { 19 | return contents[idx]; 20 | } 21 | ScalarType& operator[](int idx) { 22 | return contents[idx]; 23 | } 24 | }; 25 | 26 | // partial specialization for 2D Vectors : 27 | // -- add x() and y() accessor member functions 28 | 29 | template 30 | class Vector { 31 | ScalarType _x = 0, _y = 0; 32 | 33 | public: 34 | Vector() {} 35 | Vector(ScalarType x, ScalarType y) : _x(x), _y(y) {} 36 | 37 | ScalarType x() const { return _x; } 38 | ScalarType y() const { return _y; } 39 | 40 | ScalarType& x() { return _x; } 41 | ScalarType& y() { return _y; } 42 | 43 | ScalarType operator[](int idx) const { 44 | return idx == 0 ? _x : _y; 45 | } 46 | ScalarType& operator[](int idx) { 47 | return idx == 0 ? _x : _y; 48 | } 49 | }; 50 | 51 | // works for any "Vector"s, including partially specialized ones: 52 | 53 | template 54 | Vector operator+(const Vector& lhs, const Vector& rhs) { 55 | Vector ret; 56 | for(int i = 0; i < Length; ++i) { 57 | ret[i] = lhs[i] + rhs[i]; 58 | } 59 | return ret; 60 | } 61 | 62 | using Vec2D = Vector; 63 | 64 | int main(int argc, char** argv) { 65 | 66 | Vec2D one{ 1.0, 1.0 }; 67 | Vec2D two{ 2.0, 2.0 }; 68 | 69 | one.x(); 70 | 71 | (one + two).y(); 72 | } 73 | -------------------------------------------------------------------------------- /04_templates/04_07_class_template_arg_deduction.cpp: -------------------------------------------------------------------------------- 1 | // you can see this example working with recent GCC and Clang versions here: 2 | // https://godbolt.org/z/WzFsJp 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | class Vector { 10 | ScalarType contents[Length]; 11 | 12 | public: 13 | template 14 | Vector(Args... args) 15 | { 16 | auto init = {args...}; 17 | std::copy(init.begin(), init.end(), contents); 18 | } 19 | }; 20 | 21 | template using NthTypeOf = 22 | typename std::tuple_element>::type; 23 | 24 | // deduction guide for template "Vector": 25 | 26 | template 27 | Vector(Args... args) -> Vector, sizeof...(Args)>; 28 | 29 | int main(int argc, char** argv) { 30 | Vector one{ 1.0, 1.0, 1.0 }; 31 | static_assert(std::is_same_v>); 32 | 33 | Vector two{ 2, 2 }; 34 | static_assert(std::is_same_v>); 35 | } 36 | -------------------------------------------------------------------------------- /04_templates/04_08_variable_templates.cpp: -------------------------------------------------------------------------------- 1 | 2 | // variable template for pi 3 | 4 | template 5 | constexpr T pi = T(3.1415926535897932385L); 6 | 7 | template 8 | T circular_area(T r) // function template 9 | { 10 | return pi * r * r; // pi is a variable template instantiation 11 | } 12 | 13 | // example from variable templates proposal (N3651) 14 | -------------------------------------------------------------------------------- /04_templates/04_09_alias_templates.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Vector { 5 | using TT = Vector; 6 | 7 | ScalarType contents[Length]; 8 | 9 | public: 10 | Vector() 11 | { 12 | for(int i = 0; i < Length; ++i) contents[i] = 0; 13 | } 14 | Vector(std::initializer_list init) 15 | { 16 | std::copy(init.begin(), init.end(), contents); 17 | } 18 | 19 | ScalarType operator[](int idx) const { 20 | return contents[idx]; 21 | } 22 | ScalarType& operator[](int idx) { 23 | return contents[idx]; 24 | } 25 | }; 26 | 27 | template 28 | using Vector3 = Vector; 29 | 30 | 31 | int main(int argc, char** argv) { 32 | Vector3 bla; 33 | // equivalent to 34 | Vector bla2; 35 | } 36 | -------------------------------------------------------------------------------- /04_templates/04_10_two_phase_lookup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Non-dependent name 4 | 5 | void foo(void*) { 6 | std::cout << "foo(void*)" << std::endl; 7 | } 8 | 9 | template 10 | void non_dependent() { 11 | foo(0); 12 | } 13 | 14 | void foo(int) { 15 | std::cout << "foo(int)" << std::endl; 16 | } 17 | 18 | /// Dependent name 19 | 20 | template 21 | void dependent() { 22 | T::bar(); 23 | } 24 | 25 | struct Bar { 26 | static void bar() { 27 | std::cout << "bar" << std::endl; 28 | } 29 | }; 30 | 31 | /// Usage 32 | 33 | int main() { 34 | non_dependent(); 35 | 36 | // on Visual C++ up to and including 17, without the /fpermissive- switch, this will print 37 | // "foo(int)" 38 | // on conformant C++ compilers, it will print 39 | // "foo(void*)" 40 | 41 | // foo(0); is a non-dependent call, which means that it 42 | // should be looked up in the first phase, while the template 43 | // definition is parsed. At that point, foo(int) is not part of 44 | // the available overload set 45 | 46 | dependent(); 47 | 48 | // Bar::bar is found even though it does not exist at the 49 | // point where the template is defined 50 | } 51 | -------------------------------------------------------------------------------- /04_templates/04_11_parsing_hints.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Dependent name 4 | 5 | template 6 | void dependent() { 7 | 8 | T::print<5>(); 9 | // ^ this should not work: 10 | // since the name is dependent, it's unclear at 11 | // parse time whether it is a template 12 | // -> parsed as an expression 13 | 14 | //T::template print<5>(); 15 | // ^ disambiguate by writing "template" before the templated call 16 | } 17 | 18 | struct Bar { 19 | template 20 | static void print() { 21 | std::cout << N << std::endl; 22 | } 23 | }; 24 | 25 | /// Usage 26 | 27 | int main() { 28 | dependent(); 29 | } 30 | -------------------------------------------------------------------------------- /04_templates/04_templates.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04_templates", "04_templates.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /04_templates/04_templates.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0.15063.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v141 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v141 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v141 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v141 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | true 81 | stdcpplatest 82 | 83 | 84 | Console 85 | 86 | 87 | 88 | 89 | Level3 90 | Disabled 91 | true 92 | stdcpplatest 93 | 94 | 95 | Console 96 | 97 | 98 | 99 | 100 | Level3 101 | MaxSpeed 102 | true 103 | true 104 | true 105 | stdcpplatest 106 | 107 | 108 | true 109 | true 110 | Console 111 | 112 | 113 | 114 | 115 | Level3 116 | MaxSpeed 117 | true 118 | true 119 | true 120 | stdcpplatest 121 | 122 | 123 | true 124 | true 125 | Console 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /05_keyword_safari.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/05_keyword_safari.pdf -------------------------------------------------------------------------------- /05_keyword_safari/05_01_storage_classes.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | int global1; 4 | // global1: static storage duration, external linkage 5 | static int global2; 6 | // global2: static storage duration, internal linkage 7 | 8 | const int global3 = 4; 9 | // global3: static storage duration, *internal* linkage (must be initialized) 10 | extern const int global3; 11 | // global3: static storage duration, external linkage 12 | 13 | thread_local int thread1; 14 | // thread1: thread storage duration, external linkage 15 | thread_local static int thread2; 16 | // thread2: thread storage duration, internal linkage 17 | 18 | // unnamed namespace 19 | namespace { 20 | int in_unnamed1; 21 | // in_unnamed1: static storage duration, internal linkage 22 | extern int in_unnamed2; 23 | // in_unnamed2: static storage duration, **internal** linkage 24 | } 25 | 26 | void foo1() {} 27 | // foo1: external linkage 28 | static void foo2() {} 29 | // foo2: internal linkage 30 | 31 | 32 | void test() { 33 | int local1; 34 | // local1: automatic storage duration, no linkage 35 | static int local2; 36 | // local2: static storage duration, *no* linkage 37 | 38 | extern int local3; 39 | // local3: declares that there is a static storage duration, external linkage variable "local3" provided *somewhere* 40 | //local3 += 1; 41 | } 42 | 43 | int main() { 44 | } 45 | -------------------------------------------------------------------------------- /05_keyword_safari/05_02_static_initialization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Trace { 4 | Trace() { std::cout << "Creating Trace at " << this << std::endl; } 5 | ~Trace() { std::cout << "Destructor for Trace at " << this << std::endl; } 6 | }; 7 | 8 | void foo() { 9 | std::cout << "Beginning of foo()" << std::endl; 10 | static Trace a; 11 | std::cout << "Middle of foo()" << std::endl; 12 | Trace b; 13 | std::cout << "End of foo()" << std::endl; 14 | } 15 | 16 | 17 | int main() { 18 | std::cout << "-------- main(), Before first foo() call" << std::endl; 19 | foo(); 20 | std::cout << "-------- main(), Between foo() calls" << std::endl; 21 | foo(); 22 | std::cout << "-------- main(), End" << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /05_keyword_safari/05_03_cv_qualification.cpp: -------------------------------------------------------------------------------- 1 | 2 | void take_int_ref(int& i) {} 3 | 4 | void take_int_const_ref(const int& i) {} 5 | 6 | void take_int_volatile_ref(volatile int& i) {} 7 | 8 | void take_int_const_volatile_ref(const volatile int& i) {} 9 | 10 | 11 | int main() { 12 | 13 | int x = 0; 14 | const int cx = 0; 15 | volatile int vx = 0; 16 | const volatile int cvx = 0; 17 | 18 | take_int_ref(x); 19 | // take_int_ref(cx); // impossible -> target less qualified 20 | // take_int_ref(vx); // impossible -> target less qualified 21 | // take_int_ref(cvx); // impossible -> target less qualified 22 | 23 | take_int_const_ref(x); // fine! implicit conversion to more qualified target 24 | take_int_const_ref(cx); 25 | // take_int_const_ref(vx); // impossible -> target less qualified 26 | // take_int_const_ref(cvx); // impossible -> target less qualified 27 | 28 | take_int_volatile_ref(x); // fine! implicit conversion to more qualified target 29 | // take_int_volatile_ref(cx); // impossible -> target less qualified 30 | take_int_volatile_ref(vx); 31 | // take_int_volatile_ref(cvx); // impossible -> target less qualified 32 | 33 | take_int_const_volatile_ref(x); // fine! implicit conversion to more qualified target 34 | take_int_const_volatile_ref(cx); // fine! implicit conversion to more qualified target 35 | take_int_const_volatile_ref(vx); // fine! implicit conversion to more qualified target 36 | take_int_const_volatile_ref(cvx); 37 | 38 | 39 | /// Syntax note: for more complicated pointer types, read qualifiers right to left 40 | const int *p1; // pointer to const int 41 | int const *p2; // pointer to const int 42 | int * const p3 = nullptr; // const pointer to int 43 | int const * const p4 = nullptr; // const pointer to const int 44 | 45 | int volatile * const * volatile p5; // volatile pointer to a const pointer to a volatile integer value 46 | 47 | } 48 | -------------------------------------------------------------------------------- /05_keyword_safari/05_04_static_members.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | struct Foo { 5 | // declaration of the static data member x 6 | static int x; 7 | 8 | int y; 9 | 10 | static int bla() { 11 | // we cannot access the non-static member y 12 | // in a static context 13 | return x; 14 | } 15 | 16 | void bar() { 17 | x += y; 18 | } 19 | }; 20 | 21 | // definition of the static data member xg 22 | int Foo::x = 2; 23 | 24 | 25 | // inline static data members do not need to be defined 26 | // separately -- see https://godbolt.org/g/gBSS7V 27 | struct Bar { 28 | inline static int x; 29 | }; 30 | 31 | 32 | int main() { 33 | { 34 | // Calling a static member function by qualified name 35 | std::cout << "Foo::bla() : " << Foo::bla() << std::endl; 36 | 37 | // Calling a static member function with an instance 38 | Foo f; 39 | std::cout << "f.bla() : " << f.bla() << std::endl; 40 | 41 | // both are equivalent, the first style is preferable 42 | // since it makes the fact that bla is a static member fn clear 43 | } 44 | std::cout << std::endl; 45 | { 46 | // There is only one instance of the static data member 47 | Foo f; 48 | Foo g; 49 | 50 | std::cout << "f.x / g.x : " << f.x << " / " << g.x << std::endl; 51 | f.x += 2; 52 | std::cout << "f.x / g.x : " << f.x << " / " << g.x << std::endl; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /05_keyword_safari/05_05_explicit_constructors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Point { 4 | int x = 0, y = 0; 5 | 6 | Point() = default; 7 | Point(int p) : x(p), y(p) {} 8 | }; 9 | 10 | 11 | struct FPoint { 12 | float x = 0, y = 0; 13 | 14 | FPoint() = default; 15 | explicit FPoint(float p) : x(p), y(p) {} 16 | }; 17 | 18 | int main() { 19 | { 20 | Point p; 21 | int z = 7; 22 | // normal constructors with one argument are used 23 | // for *implicit conversion* 24 | p = z; 25 | std::cout << "p.x, p.y : " << p.x << ", " << p.y << std::endl; 26 | // this behavior can lead to situations 27 | // where erroneous program behaviour 28 | // is difficult to understand 29 | } 30 | 31 | { 32 | FPoint fp; 33 | float z = 7.f; 34 | 35 | // this line does not compile 36 | // "explicit" prevents the constructor from 37 | // being used for implicit conversion 38 | // fp = z; 39 | 40 | // this works, the cast invokes 41 | // explicit constructor conversion 42 | fp = (FPoint)z; 43 | 44 | // see: https://godbolt.org/g/fNN3Q4 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /05_keyword_safari/05_06_member_ref_qualifiers.cpp: -------------------------------------------------------------------------------- 1 | 2 | class Vector { 3 | float contents[10]; 4 | 5 | public: 6 | Vector() { } 7 | 8 | float operator[](int idx) const { 9 | return contents[idx]; 10 | } 11 | float& operator[](int idx) { 12 | return contents[idx]; 13 | } 14 | }; 15 | 16 | void error() { 17 | 18 | float& ref = Vector()[5]; 19 | ref = 7.f; 20 | } 21 | 22 | 23 | class SafeVector { 24 | float contents[10]; 25 | 26 | public: 27 | SafeVector() { } 28 | 29 | float operator[](int idx) const && { 30 | return contents[idx]; 31 | } 32 | float operator[](int idx) const & { 33 | return contents[idx]; 34 | } 35 | float& operator[](int idx) & { 36 | return contents[idx]; 37 | } 38 | }; 39 | 40 | void safe() { 41 | //float& ref = SafeVector()[5]; 42 | // ^ does not compile, 43 | // we can not access a reference from a temporary vector 44 | 45 | float val = SafeVector()[5]; 46 | 47 | const SafeVector sv; 48 | sv[4]; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /05_keyword_safari/05_07_mutable_data_members.cpp: -------------------------------------------------------------------------------- 1 | 2 | class ComplexShape { 3 | mutable bool volumeCalculated = false; 4 | mutable double volume; 5 | 6 | double calculateVolume() const { /* ... */ } 7 | 8 | public: 9 | ComplexShape( /* ... */ ) { /* ... */ } 10 | 11 | // Semantically, getVolume does not 12 | // modify the state of ComplexShape 13 | double getVolume() const { 14 | if(!volumeCalculated) { 15 | volume = calculateVolume(); 16 | volumeCalculated = true; 17 | } 18 | return volume; 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /05_keyword_safari/05_08_constexpr.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | constexpr int fac(int n) { 5 | return n <= 1 ? 1 : (n * fac(n - 1)); 6 | } 7 | 8 | // output function that requires a compile-time constant, for testing 9 | template 10 | struct constN { 11 | constN() { std::cout << n << '\n'; } 12 | }; 13 | 14 | int main() { 15 | std::cout << "4! = "; 16 | constN out1; 17 | } 18 | 19 | // https://godbolt.org/g/XoaGL9 20 | -------------------------------------------------------------------------------- /05_keyword_safari/05_09_constevalinit.cpp: -------------------------------------------------------------------------------- 1 | // Sample adapted from cppreference 2 | // Available in compiler explorer: https://godbolt.org/z/7YY3sb9YP 3 | 4 | #include 5 | 6 | // This function might be evaluated at compile-time, if the input 7 | // is known at compile-time. Otherwise, it is executed at run-time. 8 | constexpr unsigned factorial(unsigned n) { 9 | return n < 2 ? 1 : n * factorial(n - 1); 10 | } 11 | 12 | // With consteval we enforce that the function will be evaluated at compile-time. 13 | consteval unsigned combination(unsigned m, unsigned n) { 14 | return factorial(n) / factorial(m) / factorial(n - m); 15 | } 16 | 17 | // Both *can* be used in a statically/compile-time evaluated context 18 | static_assert(factorial(6) == 720); 19 | static_assert(combination(4,8) == 70); 20 | 21 | // Can also be used for static initialization with constinit 22 | constinit int g_x = factorial(2); 23 | constinit int g_y = combination(1,2); 24 | 25 | int main(int argc, const char*[]) { 26 | 27 | constexpr unsigned x{factorial(4)}; 28 | std::cout << x << '\n'; 29 | 30 | [[maybe_unused]] 31 | unsigned y = factorial(argc); // OK 32 | // unsigned z = combination(argc, 7); // error: 'argc' is not a constant expression 33 | } 34 | -------------------------------------------------------------------------------- /05_keyword_safari/05_keyword_safari.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05_keyword_safari", "05_keyword_safari.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /05_keyword_safari/05_keyword_safari.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0.15063.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v141 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v141 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v141 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v141 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | NativeRecommendedRules.ruleset 77 | false 78 | true 79 | 80 | 81 | NativeRecommendedRules.ruleset 82 | false 83 | true 84 | 85 | 86 | 87 | Level3 88 | Disabled 89 | true 90 | stdcpplatest 91 | false 92 | 93 | 94 | Console 95 | 96 | 97 | 98 | 99 | Level3 100 | Disabled 101 | true 102 | stdcpplatest 103 | false 104 | 105 | 106 | Console 107 | 108 | 109 | 110 | 111 | Level3 112 | MaxSpeed 113 | true 114 | true 115 | true 116 | stdcpplatest 117 | 118 | 119 | true 120 | true 121 | Console 122 | 123 | 124 | 125 | 126 | Level3 127 | MaxSpeed 128 | true 129 | true 130 | true 131 | stdcpplatest 132 | 133 | 134 | true 135 | true 136 | Console 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /06_advanced_templates.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/06_advanced_templates.pdf -------------------------------------------------------------------------------- /06_advanced_templates/06_01_simple_template_metafunction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct t_abs { 6 | static_assert(N != INT_MIN); 7 | static constexpr int value = (N < 0) ? -N : N; 8 | }; 9 | 10 | // t_abs is a template metafunction 11 | // parameter = "N" 12 | // return = "value" 13 | 14 | 15 | int main() { 16 | std::cout << t_abs<-5>::value << std::endl; 17 | 18 | // "t_abs<-5>::value" is the equivalent to a call 19 | // -> it requests the value member for the 20 | // instantiations with the given arguments (-5 here) 21 | } 22 | -------------------------------------------------------------------------------- /06_advanced_templates/06_02_type_parameter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct dimof { 5 | static constexpr int value = 0; 6 | }; 7 | // the base template 8 | // for the standard (non-array) case, the dimension is 0 9 | 10 | template 11 | struct dimof { 12 | static constexpr int value = 1 + dimof::value; 13 | }; 14 | // a partial specialization for types which can 15 | // be written as "T[N]" (i.e. arrays) 16 | // in this case we 17 | // - add 1 to our result value for this array dimension 18 | // - recursively invoke our metafunction by instantiating 19 | // the template for the remaining "T" 20 | 21 | int main() { 22 | std::cout << "dimof::value: " << dimof::value << std::endl; 23 | std::cout << "dimof::value: " << dimof::value << std::endl; 24 | std::cout << "dimof::value: " << dimof::value << std::endl; 25 | std::cout << "dimof::value: " << dimof::value << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /06_advanced_templates/06_03_type_result.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct remove_const { 6 | using type = T; 7 | }; 8 | // this primary template handles any type 9 | // which is *not* const-qualified 10 | 11 | template 12 | struct remove_const { 13 | using type = T; 14 | }; 15 | // specialization for const-qualified types 16 | // generates the type without qualification 17 | 18 | struct A {}; 19 | 20 | int main() { 21 | 22 | static_assert(std::is_same::type, int>::value); 23 | 24 | static_assert(std::is_same::type, float>::value); 25 | 26 | static_assert(std::is_same::type, A>::value); 27 | 28 | static_assert(std::is_same::type, volatile int>::value); 29 | 30 | std::cout << "std::is_same::type, int>::value : " 31 | << std::is_same::type, int>::value << std::endl; 32 | std::cout << "std::is_same::type, const int>::value : " 33 | << std::is_same::type, const int>::value << std::endl; 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /06_advanced_templates/06_04_refactoring_conventions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /// 1 -- Refactoring / Conventions for metafunctions returning a type 5 | 6 | template 7 | struct set_type { 8 | using type = T; 9 | }; 10 | 11 | // Refactoring: use inheritance to set the result type member: 12 | 13 | template 14 | struct remove_const : set_type {}; 15 | template 16 | struct remove_const : set_type {}; 17 | 18 | // Refactoring: create a alias template to save writing ::type everywhere 19 | // Convention: this has the suffix "_t" 20 | 21 | template 22 | using remove_const_t = typename remove_const::type; 23 | // note: "typename" here disambiguates the parsing; no longer required in C++20 24 | 25 | 26 | 27 | /// 2 -- Refactoring / Conventions for metafunctions returning a value 28 | 29 | template 30 | struct set_int { 31 | static constexpr int value = VAL; 32 | }; 33 | 34 | template 35 | struct dimof : set_int<0> {}; 36 | template 37 | struct dimof : set_int<1 + dimof::value> {}; 38 | 39 | // Refactoring: create a *variable* template to save writing ::value everywhere 40 | // Convention: this has the suffix "_v" 41 | 42 | template 43 | constexpr int dimof_v = dimof::value; 44 | 45 | 46 | 47 | /// -- Usage - note that the standard library "is_same" also follows this convention 48 | 49 | struct A {}; 50 | 51 | int main() { 52 | 53 | static_assert(std::is_same_v, int>); 54 | static_assert(std::is_same_v, float>); 55 | static_assert(std::is_same_v, A>); 56 | static_assert(std::is_same_v, volatile int>); 57 | 58 | std::cout << "dimof_v: " << dimof_v << std::endl; 59 | std::cout << "dimof_v: " << dimof_v << std::endl; 60 | std::cout << "dimof_v: " << dimof_v << std::endl; 61 | std::cout << "dimof_v: " << dimof_v << std::endl; 62 | } 63 | -------------------------------------------------------------------------------- /06_advanced_templates/06_05_tuple_includes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /// tools 5 | 6 | template 7 | struct set_bool { 8 | static constexpr bool value = VAL; 9 | }; 10 | 11 | struct true_type : set_bool {}; 12 | struct false_type : set_bool {}; 13 | 14 | 15 | /// first, we need a way to compare two types 16 | 17 | template 18 | struct is_same : false_type {}; 19 | template 20 | struct is_same : true_type {}; 21 | 22 | // We use partial specialization as a condition: 23 | // - by default, types are not the same 24 | // - iff both type arguments are the same ("is_same") 25 | // we inherit from true_type to set our return "::value" to true 26 | 27 | template 28 | constexpr bool is_same_v = is_same::value; 29 | 30 | 31 | /// now we can inspect the tuple 32 | 33 | template 34 | struct tuple_contains : false_type { 35 | }; 36 | // the base case -- we don't have the element 37 | 38 | template 39 | struct tuple_contains, T> : set_bool< 40 | is_same_v || tuple_contains, T>::value 41 | > {}; 42 | // step case -- recursion 43 | 44 | template 45 | constexpr bool tuple_contains_v = tuple_contains::value; 46 | 47 | 48 | 49 | /// -- Usage - note that the standard library "is_same" also follows this convention 50 | 51 | struct B {}; 52 | 53 | int main() { 54 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 55 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 56 | std::cout << "tuple_contains_v, B>: " << tuple_contains_v, B> << std::endl; 57 | std::cout << "tuple_contains_v, int>: " << tuple_contains_v, int> << std::endl; 58 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 59 | 60 | std::cout << "\ntuple_contains_v: " << tuple_contains_v << std::endl; 61 | // ^^ HMMMMM 62 | // do we really want this to compile? 63 | } 64 | -------------------------------------------------------------------------------- /06_advanced_templates/06_06_tuple_includes_prime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /// tools 5 | 6 | template 7 | struct set_bool { 8 | static constexpr bool value = VAL; 9 | }; 10 | 11 | struct true_type : set_bool {}; 12 | struct false_type : set_bool {}; 13 | 14 | 15 | /// first, we need a way to compare two types 16 | 17 | template 18 | struct is_same : false_type {}; 19 | template 20 | struct is_same : true_type {}; 21 | 22 | // We use partial specialization as a condition: 23 | // - by default, types are not the same 24 | // - iff both type arguments are the same ("is_same") 25 | // we inherit from true_type to set our return "::value" to true 26 | 27 | template 28 | constexpr int is_same_v = is_same::value; 29 | 30 | 31 | /// now we can inspect the tuple 32 | 33 | template 34 | struct tuple_contains { 35 | // this condition is always false when we reach this case, 36 | // but we need it to be *dependent*, which e.g. just "false" wouldn't be 37 | static_assert(sizeof(Tuple) == -1, "tuple_contains called on non-tuple"); 38 | }; 39 | 40 | template 41 | struct tuple_contains, T> : public false_type {}; 42 | 43 | template 44 | struct tuple_contains, T> : public set_bool< 45 | is_same_v || tuple_contains, T>::value 46 | > {}; 47 | 48 | template 49 | constexpr int tuple_contains_v = tuple_contains::value; 50 | 51 | 52 | 53 | /// -- Usage - note that the standard library "is_same" also follows this convention 54 | 55 | struct B {}; 56 | 57 | int main() { 58 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 59 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 60 | std::cout << "tuple_contains_v, B>: " << tuple_contains_v, B> << std::endl; 61 | std::cout << "tuple_contains_v, int>: " << tuple_contains_v, int> << std::endl; 62 | std::cout << "tuple_contains_v, float>: " << tuple_contains_v, float> << std::endl; 63 | std::cout << "tuple_contains_v, B>: " << tuple_contains_v, B> << std::endl; 64 | 65 | //std::cout << "\ntuple_contains_v: " << tuple_contains_v << std::endl; 66 | // ^^ No longer compiles, and with a nice error too 67 | } 68 | -------------------------------------------------------------------------------- /06_advanced_templates/06_07_dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Scenario: ///////////////////////////////////////////////////////////////// 4 | // we have lots of classes in our project 5 | // (maybe from different libraries) 6 | // - some can be printed with a "print_to" member function 7 | // - some can be printed using operator<< on a std stream 8 | // - they are not part of any hierarchy or specifically tagged 9 | 10 | struct A { 11 | void print_to(std::ostream& o) { 12 | o << "A\n"; 13 | } 14 | }; 15 | struct B { 16 | void print_to(std::ostream& o) { 17 | o << "B\n"; 18 | } 19 | }; 20 | struct C { 21 | void print_to(std::ostream& o) { 22 | o << "C\n"; 23 | } 24 | }; 25 | struct D { 26 | }; 27 | std::ostream& operator<<(std::ostream& o, D) { 28 | return o << "D\n"; 29 | } 30 | struct E { 31 | }; 32 | std::ostream& operator<<(std::ostream& o, E) { 33 | return o << "E\n"; 34 | } 35 | 36 | /// Goal: we want to be able to dump all these for some error reporting /////// 37 | 38 | // Option 1: implement for each of them /////////////////////////////////////// 39 | 40 | #if false 41 | void dump(A a) { 42 | a.print_to(std::cerr); 43 | } 44 | void dump(B b) { 45 | b.print_to(std::cerr); 46 | } 47 | void dump(C c) { 48 | c.print_to(std::cerr); 49 | } 50 | void dump(D d) { 51 | std::cerr << d; 52 | } 53 | void dump(E e) { 54 | std::cerr << e; 55 | } 56 | #endif 57 | 58 | // This works, but: 59 | // - it heavily violates DRY (with all the resultant complications) 60 | // - it needs to be manually extended whenever we want to dump a new class 61 | // - it is deeply unsatisfactory 62 | 63 | // Templates to the rescue? /////////////////////////////////////////////////// 64 | 65 | #if false 66 | template 67 | void dump(T t) { 68 | // ??? what now? 69 | } 70 | #endif 71 | 72 | /// Option 2: templates + metaprogramming ///////////////////////////////////// 73 | 74 | // first, we need a way to identify our objects -> a metafunction 75 | 76 | template 77 | struct has_print_to : public std::false_type {}; 78 | 79 | template 80 | struct has_print_to().print_to(std::declval()))> 82 | > : public std::true_type {}; 83 | 84 | template 85 | constexpr bool has_print_to_v = has_print_to::value; 86 | 87 | #if false 88 | 89 | // now we can write our template 90 | 91 | template 92 | std::enable_if_t> dump(T t) { 93 | t.print_to(std::cerr); 94 | } 95 | template 96 | std::enable_if_t> dump(T t) { 97 | std::cerr << t; 98 | } 99 | 100 | // Will work automatically for all classes matching the pattern 101 | 102 | #endif 103 | 104 | /// Option 3: C++17 "if constexpr" //////////////////////////////////////////// 105 | 106 | #if true 107 | 108 | // We use the same "has_print_to" trait defined above, but skip enable_if 109 | 110 | template 111 | void dump(T t) { 112 | if constexpr(has_print_to_v) { 113 | t.print_to(std::cerr); 114 | } else { 115 | std::cerr << t; 116 | } 117 | } 118 | 119 | #endif 120 | 121 | /// Usage test /////////////////////////////////////////////////////////////// 122 | 123 | int main() { 124 | A a; 125 | B b; 126 | C c; 127 | D d; 128 | E e; 129 | 130 | dump(a); 131 | dump(b); 132 | dump(c); 133 | dump(d); 134 | dump(e); 135 | } 136 | -------------------------------------------------------------------------------- /06_advanced_templates/06_08_decltype_declval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int fun(); // NOTE: "fun" has no body 5 | // -> using it in an evaluated context would be an error 6 | 7 | int main() { 8 | 9 | decltype(5u + 7u) y; 10 | // equivalent to "unsigned y;" 11 | 12 | decltype(std::declval() * std::declval()) z; 13 | // equivalent to "double z;" 14 | 15 | decltype(std::declval().cbegin()) iterator; 16 | // equivalent to "std::string::const_iterator iterator;" 17 | 18 | decltype(fun()) x; 19 | // equivalent to "int x;" 20 | // we can use fun here since it is an unevaluated context 21 | 22 | std::cout << sizeof(fun()) << std::endl; 23 | // also allowed -- also an unevaluated context 24 | 25 | //fun(); 26 | // ^ this causes a linker error (used in evaluated context) 27 | } 28 | -------------------------------------------------------------------------------- /06_advanced_templates/06_09_sfinae.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | bool is_odd(int[1][N % 2 == 1 ? 1 : -1] = nullptr) { 6 | return true; 7 | } 8 | 9 | template 10 | bool is_odd(int[1][N % 2 == 0 ? 1 : -1] = nullptr) { 11 | return false; 12 | } 13 | 14 | int main() { 15 | 16 | //int x[-1]; 17 | // ^ this is a compiler error - we can't use a negative array length 18 | 19 | std::cout << "is_odd<0>() : " << is_odd<0>() << std::endl; 20 | std::cout << "is_odd<1>() : " << is_odd<1>() << std::endl; 21 | std::cout << "is_odd<33>() : " << is_odd<33>() << std::endl; 22 | std::cout << "is_odd<42>() : " << is_odd<42>() << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /06_advanced_templates/06_10_crtp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct Base { 5 | void operation() { 6 | std::cout << "- perform some general work in Base..." << std::endl; 7 | static_cast(this)->implementation(); 8 | std::cout << "- more general work in Base..." << std::endl; 9 | } 10 | }; 11 | 12 | struct Derived : Base { // CRTP! 13 | void implementation() { 14 | std::cout << "! specialized work in Derived..." << std::endl; 15 | } 16 | }; 17 | 18 | int main() { 19 | 20 | // this setup allows us to perform 21 | // polymorphism-like customization without dynamic dispatch! 22 | Derived d; 23 | d.operation(); 24 | } 25 | -------------------------------------------------------------------------------- /06_advanced_templates/06_advanced_templates.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "06_advanced_templates", "06_advanced_templates.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /06_advanced_templates/06_advanced_templates.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0.15063.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v141 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v141 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v141 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v141 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | NativeRecommendedRules.ruleset 77 | false 78 | true 79 | 80 | 81 | NativeRecommendedRules.ruleset 82 | false 83 | true 84 | 85 | 86 | 87 | Level3 88 | Disabled 89 | true 90 | stdcpplatest 91 | false 92 | 93 | 94 | Console 95 | 96 | 97 | 98 | 99 | Level3 100 | Disabled 101 | true 102 | stdcpplatest 103 | false 104 | 105 | 106 | Console 107 | 108 | 109 | 110 | 111 | Level3 112 | MaxSpeed 113 | true 114 | true 115 | true 116 | stdcpplatest 117 | 118 | 119 | true 120 | true 121 | Console 122 | 123 | 124 | 125 | 126 | Level3 127 | MaxSpeed 128 | true 129 | true 130 | true 131 | stdcpplatest 132 | 133 | 134 | true 135 | true 136 | Console 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /07_concepts.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/07_concepts.pdf -------------------------------------------------------------------------------- /07_concepts/07_01_basic_sample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std::literals; 6 | 7 | // Declaration of the concept "Hashable", which is satisfied by 8 | // any type 'T' such that for values 'a' of type 'T', 9 | // the expression std::hash{}(a) compiles 10 | template 11 | concept Hashable = requires(T a) { 12 | std::hash{}(a); 13 | }; 14 | 15 | template 16 | requires Hashable 17 | void fun(T) { 18 | // ... internal code 19 | std::hash(T); 20 | // ... internal code 21 | } 22 | 23 | struct meow {}; 24 | 25 | int main() { 26 | fun("abc"s); // OK, std::string satisfies Hashable 27 | fun(meow{}); // Error: meow does not satisfy Hashable 28 | } 29 | -------------------------------------------------------------------------------- /07_concepts/07_02_syntax_options.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | concept Hashable = requires(T a) { 7 | std::hash{}(a); 8 | }; 9 | 10 | // can appear as the last element of a function declarator 11 | template 12 | void f(T&&) requires Hashable; 13 | 14 | // or right after a template parameter list 15 | template 16 | requires Hashable void g(T&&); 17 | 18 | #if 0 19 | 20 | // Kind-of-terse syntax 21 | 22 | template 23 | void fun(T) {} 24 | 25 | #else 26 | 27 | // requires clause after signature is also possible 28 | 29 | template 30 | void fun(T) requires Hashable {} 31 | 32 | #endif 33 | 34 | struct meow {}; 35 | 36 | int main() { 37 | fun(10); // OK, int satisfies Hashable 38 | //fun(meow{}); // Error: meow does not satisfy Hashable 39 | } 40 | -------------------------------------------------------------------------------- /07_concepts/07_03_constrained_auto.cpp: -------------------------------------------------------------------------------- 1 | // note: this is currently not supported in MSVC 16.8 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | concept Hashable = requires(T a) { 9 | std::hash{}(a); 10 | }; 11 | 12 | // Terse syntax 13 | 14 | void fun(Hashable auto x) {} 15 | 16 | // note: must be directly preceding auto: 17 | 18 | void more_fun(const Hashable auto x) {} 19 | 20 | // void less_fun(Hashable const auto x) {} // incorrect 21 | 22 | int main() { 23 | // also applicable to variables! 24 | 25 | Hashable auto str = "Hello"; 26 | } 27 | -------------------------------------------------------------------------------- /07_concepts/07_04_requires_expression.cpp: -------------------------------------------------------------------------------- 1 | 2 | // basic requires expression in a concept definition 3 | template 4 | concept Addable = requires(T x) { 5 | x + x; 6 | }; 7 | 8 | // this is a requires-clause, not requires-expression 9 | template 10 | requires Addable 11 | T add(T a, T b) { 12 | return a + b; 13 | } 14 | 15 | // ad-hoc constraint, note keyword used twice 16 | // first one starts a requires-clause, second a requires-expression 17 | template 18 | requires requires(T x) { 19 | x + x; 20 | } 21 | T add(T a, T b) { 22 | return a + b; 23 | } 24 | // this is very ugly, but to an extent at least it's intentionally 25 | // and justifiably ugly: 26 | // if you need a given set of constraints you should almost always 27 | // have reason to give it a meaningful name, and likely reuse it 28 | 29 | 30 | class stream; 31 | 32 | // note that parameters introduced by the requires expression 33 | // have *no storage, linkage or lifetime*. 34 | // They are constructs purely for compile-time type checking 35 | template 36 | concept Streamable = requires(T x, stream s) { 37 | s << x; 38 | }; 39 | -------------------------------------------------------------------------------- /07_concepts/07_05_requirements.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Simple Requirements 5 | // ------------------- 6 | 7 | template 8 | concept Addable = requires(T a, T b) { 9 | a + b; // "the expression a+b is a valid expression that will compile" 10 | }; 11 | 12 | template 13 | concept Swappable = requires(T&& t, U&& u) { 14 | std::swap(std::forward(t), std::forward(u)); 15 | std::swap(std::forward(u), std::forward(t)); 16 | }; 17 | 18 | // Type Requirements 19 | // ----------------- 20 | 21 | template 22 | using Ref = T&; 23 | 24 | template 25 | struct S {}; 26 | 27 | template 28 | concept TypeRequirements = requires { 29 | typename T::inner; // required nested member name 30 | typename S; // required class template specialization 31 | typename Ref; // required alias template substitution 32 | }; 33 | 34 | // Compound Requirements 35 | // --------------------- 36 | 37 | template 38 | concept CompoundRequirements = requires(T x) { 39 | { *x } -> std::convertible_to; 40 | // the expression *x must be valid 41 | // AND the type T::inner must be valid 42 | // AND the result of *x must be convertible to T::inner 43 | 44 | { x + 1 } -> std::same_as; 45 | // the expression x + 1 must be valid 46 | // AND std::same_as must be satisfied 47 | // i.e., (x + 1) must be a prvalue of type int 48 | 49 | { x * 1 } noexcept -> std::convertible_to; 50 | // the expression x * 1 must be valid 51 | // AND x * 1 must not be potentially throwing 52 | // AND its result must be convertible to T 53 | }; 54 | 55 | // Nested Requirements 56 | // ------------------- 57 | 58 | template 59 | concept Semiregular = 60 | std::default_initializable && std::copy_constructible && std::destructible 61 | && requires(T a, std::size_t n) { 62 | requires std::same_as; // nested: "Same<...> evaluates to true" 63 | { a.~T() } noexcept; // compound: "a.~T()" is a valid expression that doesn't throw 64 | requires std::same_as; // nested: "Same<...> evaluates to true" 65 | requires std::same_as; // nested 66 | {delete new T}; // compound 67 | {delete new T[n]}; // compound 68 | }; 69 | -------------------------------------------------------------------------------- /07_concepts/07_06_dispatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Scenario: ///////////////////////////////////////////////////////////////// 4 | // we have lots of classes in our project 5 | // (maybe from different libraries) 6 | // - some can be printed with a "print_to" member function 7 | // - some can be printed using operator<< on a std stream 8 | // - they are not part of any hierarchy or specifically tagged 9 | 10 | struct A { 11 | void print_to(std::ostream& o) { 12 | o << "A\n"; 13 | } 14 | }; 15 | struct B { 16 | void print_to(std::ostream& o) { 17 | o << "B\n"; 18 | } 19 | }; 20 | struct C { 21 | void print_to(std::ostream& o) { 22 | o << "C\n"; 23 | } 24 | }; 25 | struct D { 26 | }; 27 | std::ostream& operator<<(std::ostream& o, D) { 28 | return o << "D\n"; 29 | } 30 | struct E { 31 | }; 32 | std::ostream& operator<<(std::ostream& o, E) { 33 | return o << "E\n"; 34 | } 35 | 36 | // not printable with either method 37 | struct F {}; 38 | 39 | /// Goal: we want to be able to dump all these for some error reporting /////// 40 | 41 | template 42 | concept stream_printable = 43 | requires(T t, std::ostream& o) { o << t; }; 44 | 45 | template 46 | void dump(T t) { 47 | std::cerr << t; 48 | } 49 | 50 | template 51 | concept print_to_printable = 52 | requires(T t, std::ostream& o) { t.print_to(o); }; 53 | 54 | template 55 | void dump(T t) { 56 | t.print_to(std::cerr); 57 | } 58 | 59 | /// Usage test /////////////////////////////////////////////////////////////// 60 | 61 | int main() { 62 | A a; 63 | B b; 64 | C c; 65 | D d; 66 | E e; 67 | F f; 68 | 69 | dump(a); 70 | dump(b); 71 | dump(c); 72 | dump(d); 73 | dump(e); 74 | // dump(f); // automatically get useful errors -- at the call site! 75 | } 76 | -------------------------------------------------------------------------------- /07_concepts/07_07_partial_order.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | concept Decrementable = requires(T t) { 5 | --t; 6 | }; 7 | template 8 | concept RevIterator = Decrementable&& requires(T t) { 9 | *t; 10 | }; 11 | 12 | // RevIterator subsumes Decrementable, but not the other way around 13 | 14 | template 15 | void f(T) { std::cout << "#1\n"; } // #1 16 | 17 | template 18 | void f(T) { std::cout << "#2\n"; } // #2, more constrained than #1 19 | 20 | void test1() { 21 | f(0); // int only satisfies Decrementable, selects #1 22 | f((int*)0); // int* satisfies both constraints, selects #2 as more constrained 23 | } 24 | 25 | template 26 | void g(T) { std::cout << "#3\n"; } // #3 (unconstrained) 27 | 28 | template 29 | void g(T) { std::cout << "#4\n"; } // #4 30 | 31 | void test2() { 32 | g(true); // bool does not satisfy Decrementable, selects #3 33 | g(0); // int satisfies Decrementable, selects #4 because it is more constrained 34 | } 35 | 36 | template 37 | concept RevIterator2 = requires(T t) { 38 | --t; 39 | *t; 40 | }; 41 | 42 | template 43 | void h(T); // #5 44 | 45 | template 46 | void h(T); // #6 47 | 48 | void test3() { 49 | //h((int*)0); // ambiguous 50 | } 51 | 52 | int main() { 53 | test1(); 54 | test2(); 55 | } -------------------------------------------------------------------------------- /07_concepts/07_concepts.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "07_concepts", "07_concepts.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /07_concepts/07_concepts.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v142 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v142 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v142 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v142 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | NativeRecommendedRules.ruleset 77 | false 78 | true 79 | D:\dev\eigen;$(IncludePath) 80 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 81 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 82 | 83 | 84 | NativeRecommendedRules.ruleset 85 | false 86 | true 87 | D:\dev\eigen;$(IncludePath) 88 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 89 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 90 | 91 | 92 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 93 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 94 | 95 | 96 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 97 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | true 104 | stdcpplatest 105 | false 106 | 107 | 108 | Console 109 | 110 | 111 | 112 | 113 | Level3 114 | Disabled 115 | true 116 | stdcpplatest 117 | false 118 | 119 | 120 | Console 121 | 122 | 123 | 124 | 125 | Level3 126 | MaxSpeed 127 | true 128 | true 129 | true 130 | stdcpplatest 131 | 132 | 133 | true 134 | true 135 | Console 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | stdcpplatest 146 | 147 | 148 | true 149 | true 150 | Console 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /08_libraries.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PeterTh/uibk_cpp/43adc813c07a29afd48048eba9dae1730b9383fb/08_libraries.pdf -------------------------------------------------------------------------------- /08_libraries/08_01_regex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | std::string s = R"( 7 | Some people, when confronted with a problem, think 8 | "I know, I'll use regular expressions." 9 | Now they have two problems.)"; 10 | 11 | // ^ Note: raw string syntax 12 | 13 | /// check for a single match 14 | 15 | std::regex self_regex("REGULAR EXPRESSIONS?", 16 | std::regex_constants::ECMAScript | std::regex_constants::icase); 17 | // ^ equivalent to just std::regex_constants::icase (ECMAScript is the default) 18 | 19 | if(std::regex_search(s, self_regex)) { 20 | std::cout << "Text contains the phrase 'regular expression[s]'\n"; 21 | } 22 | 23 | /// iterate over all matches using a regex_iterator 24 | 25 | std::regex word_regex(R"(['\w]+)"); 26 | auto words_begin = 27 | std::sregex_iterator(s.begin(), s.end(), word_regex); 28 | auto words_end = std::sregex_iterator(); 29 | 30 | std::cout << "Found " 31 | << std::distance(words_begin, words_end) 32 | << " words\n"; 33 | 34 | const int N = 6; 35 | std::cout << "Words longer than " << N << " characters:\n"; 36 | for(auto i = words_begin; i != words_end; ++i) { 37 | std::string match_str = i->str(); 38 | if(match_str.size() > N) { 39 | std::cout << " " << match_str << '\n'; 40 | } 41 | } 42 | 43 | /// find words with 6 or more characters and put the first character in brackets 44 | 45 | std::regex long_word_regex(R"((\w)(\w{5,}))"); 46 | std::string new_s = std::regex_replace(s, long_word_regex, "[$1]$2"); 47 | std::cout << new_s << '\n'; 48 | } 49 | -------------------------------------------------------------------------------- /08_libraries/08_02_threads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void replace_string_thread(std::string& target, std::mutex& target_mutex, 7 | const std::string to_replace, const std::string replacement) { 8 | std::lock_guard lock(target_mutex); 9 | // ^ in C++17 we can omit the template parameter (deduction guides) 10 | // in earlier versions we need to explicitly write "" 11 | // lock_guard is a *scoped lock* 12 | target.replace(target.find(to_replace), to_replace.size(), replacement); 13 | } 14 | 15 | int main() { 16 | 17 | std::string message{ "Hello World" }; 18 | std::mutex message_mutex; 19 | 20 | std::cout << message << std::endl; 21 | 22 | /// Create two threads to manipulate the message string 23 | 24 | std::thread replace_world(replace_string_thread, 25 | std::ref(message), std::ref(message_mutex), "World", "Program"); 26 | std::thread replace_hello(replace_string_thread, 27 | std::ref(message), std::ref(message_mutex), "Hello", "Goodbye"); 28 | 29 | // NOTE the usage of std::ref to pass references to 30 | // the replace_string_thread function 31 | // (std::thread tries to move or copy its arguments) 32 | 33 | /// Wait for thread completion 34 | 35 | replace_world.join(); 36 | replace_hello.join(); 37 | 38 | std::cout << message << std::endl; 39 | } 40 | -------------------------------------------------------------------------------- /08_libraries/08_03_future_fs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | namespace fs = std::filesystem; 8 | 9 | // Note: needs to be linked with -lstdc++fs (in GCC 8.2) 10 | // experimental in earlier compilers 11 | 12 | int main() { 13 | using namespace std::chrono_literals; 14 | 15 | auto largest_future = std::async([]() { 16 | // find largest file in working directory 17 | std::uintmax_t largest_size = 0; 18 | fs::path largest; 19 | try { 20 | for(auto& p : fs::recursive_directory_iterator(".")) { 21 | if(p.is_regular_file()) { 22 | auto path = p.path(); 23 | auto s = fs::file_size(path); 24 | if(s > largest_size) { 25 | largest_size = s; 26 | largest = path; 27 | } 28 | } 29 | } 30 | } 31 | // when dealing with files, getting an exception isn't unlikely 32 | catch(std::exception& e) { 33 | std::cerr << std::endl << "Exception: " << e.what() << std::endl; 34 | } 35 | return largest; 36 | }); 37 | 38 | std::cout << "Searching for largest file..."; 39 | 40 | // ... other work / progress bar / etc 41 | while(largest_future.wait_for(250ms) != std::future_status::ready) { 42 | std::cout << "."; 43 | } 44 | 45 | std::cout << std::endl << "Largest file: " << largest_future.get().generic_string() << std::endl; 46 | } 47 | -------------------------------------------------------------------------------- /08_libraries/08_04_boost_format.cpp: -------------------------------------------------------------------------------- 1 | // adapted from boost::format example 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "boost/format.hpp" 8 | 9 | namespace for_output { 10 | using std::cout; 11 | using std::cerr; 12 | using std::string; 13 | using std::endl; 14 | using std::flush; 15 | 16 | using boost::format; 17 | } 18 | 19 | int main() { 20 | using namespace for_output; 21 | 22 | std::cout << format("%|1$1| %|2$3|") % "Hello" % 3 << std::endl; 23 | 24 | /// Reordering : 25 | cout << format("%1% %2% %3% %2% %1% \n") % "o" % "oo" % "O"; // 'simple' style. 26 | // prints "o oo O oo o \n" 27 | cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35; // Posix-Printf style 28 | 29 | 30 | /// No reordering : 31 | cout << format("writing %s, x=%s : %d-th step \n") % "toto" % 40.23 % 50; 32 | // prints "writing toto, x=40.23 : 50-th step \n" 33 | 34 | cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35; 35 | cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35; 36 | cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35; 37 | // all those are the same, it prints "(x,y) = ( -23, +35) \n" 38 | 39 | 40 | /// printf directives' type-flag can be used to pass formatting options : 41 | cout << format("_%1$4d_ is : _%1$#4x_, _%1$#4o_, and _%1$s_ by default\n") % 18; 42 | // prints "_ 18_ is : _0x12_, _ 022_, and _18_ by default\n" 43 | 44 | 45 | /// Taking the string value : 46 | std::string s; 47 | s = str(format(" %d %d ") % 11 % 22); 48 | assert(s == " 11 22 "); 49 | 50 | 51 | /// %% prints '%' 52 | cout << format("%%##%#x ") % 20 << endl; 53 | // prints "%##0x14 " 54 | 55 | 56 | /// Enforcing the right number of arguments 57 | 58 | // Too many arguments will throw an exception when feeding the unwanted argument : 59 | try { 60 | format(" %1% %1% ") % 101 % 102; 61 | // the format-string refers to ONE argument, twice. not 2 arguments. 62 | // thus giving 2 arguments is an error 63 | } 64 | catch(boost::io::too_many_args& exc) { 65 | cerr << exc.what() << "\n\t\t***Dont worry, that was planned\n"; 66 | } 67 | 68 | // Too few arguments when requesting the result will also throw an exception : 69 | try { 70 | cerr << format(" %|3$| ") % 101; 71 | // even if %1$ and %2$ are not used, you should have given 3 arguments 72 | } 73 | catch(boost::io::too_few_args& exc) { 74 | cerr << exc.what() << "\n\t\t***Dont worry, that was planned\n"; 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /08_libraries/08_05_boost_bimap.cpp: -------------------------------------------------------------------------------- 1 | // adapted from boost::bimap example 2 | 3 | #include 4 | #include 5 | 6 | #include "boost/bimap.hpp" 7 | 8 | // helper to print maps 9 | template 10 | void print_map(const MapType& map, const std::string& separator, std::ostream& os) { 11 | for(auto p : map) { 12 | os << p.first << separator << p.second << std::endl; 13 | } 14 | } 15 | 16 | int main() { 17 | boost::bimap results; 18 | results.insert({ "Argentina", 1 }); 19 | results.insert({ "Spain" , 2 }); 20 | results.insert({ "Germany" , 3 }); 21 | results.insert({ "France" , 4 }); 22 | 23 | std::cout << "The number of countries is " << results.size() << std::endl; 24 | 25 | std::cout << "Germany ended up in position " << results.left.at("Germany") << std::endl; 26 | // ^ map lookup by left-hand side 27 | std::cout << "The winner is " << results.right.at(1) << std::endl << std::endl; 28 | // ^ map lookup by right-hand side 29 | 30 | std::cout << "Countries names ordered by their final position:" << std::endl; 31 | print_map(results.right, ") ", std::cout); 32 | // ^ results.right works like a std::map 33 | std::cout << std::endl; 34 | 35 | std::cout << std::endl << "Countries names ordered alphabetically along with their final position:" << std::endl; 36 | print_map(results.left, " ends in position ", std::cout); 37 | // ^ results.left works like a std::map 38 | std::cout << std::endl; 39 | } 40 | -------------------------------------------------------------------------------- /08_libraries/08_06_boost_operators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | template 8 | class Vec2D // note: private inheritance is OK here! 9 | : boost::addable< Vec2D // point + point 10 | , boost::subtractable< Vec2D // point - point 11 | , boost::dividable2< Vec2D, T // point / T 12 | , boost::multipliable2< Vec2D, T // point * T, T * point 13 | > > > > // note: base class chaining technique 14 | { 15 | T x_; 16 | T y_; 17 | 18 | public: 19 | Vec2D(T x, T y) : x_(x), y_(y) { 20 | } 21 | T x() const { 22 | return x_; 23 | } 24 | T y() const { 25 | return y_; 26 | } 27 | 28 | Vec2D operator+=(const Vec2D& other) { 29 | x_ += other.x_; 30 | y_ += other.y_; 31 | return *this; 32 | } 33 | // point operator+(point, const point&) automatically 34 | // generated by addable. 35 | 36 | Vec2D operator-=(const Vec2D& other) { 37 | x_ -= other.x_; 38 | y_ -= other.y_; 39 | return *this; 40 | } 41 | // point operator-(point, const point&) automatically 42 | // generated by subtractable. 43 | 44 | Vec2D operator*=(T other) { 45 | x_ *= other; 46 | y_ *= other; 47 | return *this; 48 | } 49 | // point operator*(point, const T&) and 50 | // point operator*(const T&, point) auto-generated 51 | // by multipliable. 52 | 53 | Vec2D operator/=(T other) { 54 | x_ /= other; 55 | y_ /= other; 56 | return *this; 57 | } 58 | // point operator/(point, const T&) auto-generated 59 | // by dividable. 60 | }; 61 | 62 | /// Base class chaining result: 63 | /// chained unchained 64 | /// binary ; sizeof(Vec2D) binary ; sizeof(Vec2D) 65 | /// VS2017.5 10752 8 10752 12 66 | /// GCC4.8.5 8992 8 8984 8 67 | /// Clang3.5 - 8 - 8 68 | /// ICC13 - 8 - 8 69 | 70 | // now use the Vec2D class: 71 | 72 | template 73 | T length(const Vec2D p) { 74 | return sqrt(p.x()*p.x() + p.y()*p.y()); 75 | } 76 | 77 | int main() { 78 | const Vec2D right(0, 1); 79 | const Vec2D up(1, 0); 80 | const Vec2D pi_over_4 = up + right; 81 | const Vec2D pi_over_4_normalized = pi_over_4 / length(pi_over_4); 82 | 83 | std::cout << sizeof(Vec2D) << std::endl; 84 | } 85 | -------------------------------------------------------------------------------- /08_libraries/08_07_boost_hana.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /// Scenario: ///////////////////////////////////////////////////////////////// 4 | // we have lots of classes in our project 5 | // (maybe from different libraries) 6 | // - some can be printed with a "print_to" member function 7 | // - some can be printed using operator<< on a std stream 8 | // - they are not part of any hierarchy or specifically tagged 9 | 10 | struct A { 11 | void print_to(std::ostream& o) { 12 | o << "A\n"; 13 | } 14 | }; 15 | struct B { 16 | void print_to(std::ostream& o) { 17 | o << "B\n"; 18 | } 19 | }; 20 | struct C { 21 | void print_to(std::ostream& o) { 22 | o << "C\n"; 23 | } 24 | }; 25 | struct D { 26 | }; 27 | std::ostream& operator<<(std::ostream& o, D) { 28 | return o << "D\n"; 29 | } 30 | struct E { 31 | }; 32 | std::ostream& operator<<(std::ostream& o, E) { 33 | return o << "E\n"; 34 | } 35 | 36 | /// Goal: we want to be able to dump all these for some error reporting /////// 37 | 38 | #include 39 | namespace hana = boost::hana; 40 | 41 | template 42 | void dump(T t) { 43 | hana::if_(hana::is_valid([](auto t) -> decltype(t.print_to(std::cerr)) {})(t), 44 | [](auto&& t) { t.print_to(std::cerr); }, 45 | [](auto&& t) { std::cerr << t; } 46 | )(std::forward(t)); 47 | } 48 | 49 | // C++ 17: 50 | 51 | #if 0 52 | template 53 | void dump(T t) { 54 | if constexpr(hana::is_valid([](auto t) -> decltype(t.print_to(std::cerr)) {})(t)) { 55 | t.print_to(std::cerr); 56 | } 57 | else { 58 | std::cerr << t; 59 | } 60 | } 61 | #endif 62 | 63 | /// Usage test /////////////////////////////////////////////////////////////// 64 | 65 | int main() { 66 | A a; 67 | B b; 68 | C c; 69 | D d; 70 | E e; 71 | 72 | dump(a); 73 | dump(b); 74 | dump(c); 75 | dump(d); 76 | dump(e); 77 | } 78 | -------------------------------------------------------------------------------- /08_libraries/08_08_boost_program_options.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace po = boost::program_options; 8 | 9 | int main(int argc, char **argv) { 10 | 11 | int opt; 12 | 13 | // Declare the supported options. 14 | po::options_description desc("Program options"); 15 | desc.add_options() 16 | ("help", "produce help message") 17 | ("optimization", po::value(&opt)->default_value(10), "optimization level") 18 | ("include-path,I", po::value>()->multitoken(), "include path") 19 | ("input-file", po::value>(), "input file") 20 | ; 21 | 22 | po::variables_map vm; 23 | po::store(po::parse_command_line(argc, argv, desc), vm); 24 | po::notify(vm); 25 | 26 | if(vm.count("help")) { 27 | std::cout << desc << "\n"; 28 | return 1; 29 | } 30 | 31 | if(vm.count("include-path")) { 32 | auto paths = vm["include-path"].as>(); 33 | std::cout << "Number of include paths: " << paths.size() << std::endl; 34 | for(auto p : paths) { 35 | std::cout << " " << p << std::endl; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /08_libraries/08_09_boost_log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /// linking: 12 | // -lboost_log 13 | // -DBOOST_LOG_DYN_LINK 14 | 15 | namespace logging = boost::log; 16 | 17 | /// setup example 18 | 19 | void log_init() { 20 | logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::debug); 21 | // ^ globally filter out log messages of lower importance than "debug" 22 | 23 | logging::add_common_attributes(); 24 | // ^ enable common log message attributes such as timestamps 25 | 26 | logging::add_console_log(std::cout, 27 | logging::keywords::format = "%Message% (%TimeStamp%)", 28 | logging::keywords::filter = logging::trivial::severity >= logging::trivial::warning 29 | ); 30 | // ^ log all messages of "warning" level or higher to std::cout in the given format 31 | 32 | logging::add_file_log( 33 | logging::keywords::file_name = "test.log", 34 | logging::keywords::rotation_size = 10 * 1024 * 1024, 35 | logging::keywords::format = "[%TimeStamp%]: %Message%" 36 | ); 37 | // ^ log all messages not globally filtered out to "test.log" 38 | // keep a maximum of 10 MiB of logging information 39 | } 40 | 41 | /// usage 42 | 43 | int main() { 44 | log_init(); 45 | 46 | BOOST_LOG_TRIVIAL(trace) << "A trace severity message"; 47 | BOOST_LOG_TRIVIAL(debug) << "A debug severity message"; 48 | BOOST_LOG_TRIVIAL(info) << "An informational severity message"; 49 | BOOST_LOG_TRIVIAL(warning) << "A warning severity message"; 50 | BOOST_LOG_TRIVIAL(error) << "An error severity message"; 51 | BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message"; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /08_libraries/08_10_eigen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | using namespace Eigen; 5 | 6 | int main() { 7 | 8 | // simple arithmetic 9 | 10 | Matrix2d a; 11 | a << 1, 2, 12 | 3, 4; 13 | MatrixXd b(2, 2); 14 | b << 2, 3, 15 | 1, 4; 16 | std::cout << "a + b =\n" << a + b << std::endl; 17 | std::cout << "a - b =\n" << a - b << std::endl; 18 | 19 | Vector3d v(1, 2, 3); 20 | Vector3d w(1, 0, 0); 21 | std::cout << std::endl << "-v + w - v =\n" << -v + w - v << std::endl; 22 | 23 | 24 | // row / column operations 25 | 26 | Matrix3d m; 27 | m << 1, 2, 3, 28 | 4, 5, 6, 29 | 7, 8, 9; 30 | double alpha = 0.5; 31 | double beta = 2.0; 32 | std::cout << std::endl << "m1\n" << m << std::endl;; 33 | 34 | m.row(0) += alpha * m.row(1); 35 | std::cout << std::endl << "m2\n" << m << std::endl;; 36 | 37 | m.col(1) = alpha * m.col(2) + beta * m.col(0); 38 | std::cout << std::endl << "m3\n" << m << std::endl;; 39 | 40 | m.col(2).swap(m.col(1)); 41 | std::cout << std::endl << "m4\n" << m << std::endl;; 42 | } 43 | -------------------------------------------------------------------------------- /08_libraries/08_libraries.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.16 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "08_libraries", "08_libraries.vcxproj", "{73494179-559F-4E77-8FF9-6DC5A65CF6AE}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.ActiveCfg = Debug|x64 17 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x64.Build.0 = Debug|x64 18 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.ActiveCfg = Debug|Win32 19 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Debug|x86.Build.0 = Debug|Win32 20 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.ActiveCfg = Release|x64 21 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x64.Build.0 = Release|x64 22 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.ActiveCfg = Release|Win32 23 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {0B140BBB-CA06-4DAC-8916-AC07A0F8F6D3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /08_libraries/08_libraries.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 15.0 26 | {73494179-559F-4E77-8FF9-6DC5A65CF6AE} 27 | 03_lambdas_and_algorithms 28 | 10.0.15063.0 29 | 30 | 31 | 32 | Application 33 | true 34 | v141 35 | MultiByte 36 | 37 | 38 | Application 39 | false 40 | v141 41 | true 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v141 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v141 54 | true 55 | MultiByte 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | NativeRecommendedRules.ruleset 77 | false 78 | true 79 | D:\dev\eigen;$(IncludePath) 80 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 81 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 82 | 83 | 84 | NativeRecommendedRules.ruleset 85 | false 86 | true 87 | D:\dev\eigen;$(IncludePath) 88 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 89 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 90 | 91 | 92 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 93 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 94 | 95 | 96 | $(TMP)\$(ProjectName)\$(Platform)\$(Configuration)\ 97 | $(TMP)\$(ProjectName)\tmp\$(Platform)\$(Configuration)\ 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | true 104 | stdcpplatest 105 | false 106 | 107 | 108 | Console 109 | 110 | 111 | 112 | 113 | Level3 114 | Disabled 115 | true 116 | stdcpplatest 117 | false 118 | 119 | 120 | Console 121 | 122 | 123 | 124 | 125 | Level3 126 | MaxSpeed 127 | true 128 | true 129 | true 130 | stdcpplatest 131 | 132 | 133 | true 134 | true 135 | Console 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | stdcpplatest 146 | 147 | 148 | true 149 | true 150 | Console 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UIBK Lecture on Advanced C++ 2 | 3 | This repository contains all lecture material. 4 | Slide sets are provided as .pdf files in the root directory, and the code accompanying each lecture is in its respective subfolder (e.g. `01_values/01_01_basic_values.cpp`). 5 | 6 | Introduction and management information can be found in **00_introduction.pdf**. 7 | 8 | ## Video recordings 9 | 10 | *Some* lecture recordings from 2018 are available: 11 | 12 | - [Lecture 4 - Interface Design: Classes](https://www.youtube.com/watch?v=MQKgGe2sK-o) 13 | - [Lecture 5 - Generic Programming with Templates](https://www.youtube.com/watch?v=KqSeUJUzSEU) 14 | - [Lecture 7 - Keyword Safari](https://www.youtube.com/watch?v=iv3wC2a3yMY) 15 | - [Lecture 8 - Advanced Templates (Part 1/2)](https://www.youtube.com/watch?v=ZThiFvFaZPA) 16 | - [Lecture 9 - Advanced Templates (Part 2/2)](https://www.youtube.com/watch?v=aveAk5BSf5I) 17 | 18 | Complete stream VODs from the 2020 lecture are available in the following Youtube playlist: 19 | 20 | [Advanced C++ Lecture Stream 2020/2021](https://youtube.com/playlist?list=PLgZYa2uwsRM6jQZwlJT8EHm_NHvbLnF46) 21 | --------------------------------------------------------------------------------