Commit 0400e7fe authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Revamp exercices of part 5.

parent d933f272
......@@ -12,15 +12,15 @@
"metadata": {},
"source": [
"* [Error handling](/notebooks/5-UsefulConceptsAndSTL/1-ErrorHandling.ipynb)\n",
" * [TP 13](/notebooks/5-UsefulConceptsAndSTL/1b-TP.ipynb)\n",
" * [TP 14](/notebooks/5-UsefulConceptsAndSTL/1b-TP.ipynb)\n",
"* [RAII idiom](/notebooks/5-UsefulConceptsAndSTL/2-RAII.ipynb)\n",
"* [Containers](/notebooks/5-UsefulConceptsAndSTL/3-Containers.ipynb)\n",
" * [TP 14](/notebooks/5-UsefulConceptsAndSTL/3b-TP.ipynb)\n",
" * [TP 15](/notebooks/5-UsefulConceptsAndSTL/3b-TP.ipynb)\n",
"* [Associative containers](/notebooks/5-UsefulConceptsAndSTL/4-AssociativeContainers.ipynb)\n",
"* [Move semantics](/notebooks/5-UsefulConceptsAndSTL/5-MoveSemantics.ipynb)\n",
" * [TP 15](/notebooks/5-UsefulConceptsAndSTL/5b-TP.ipynb)\n",
" * [TP 16](/notebooks/5-UsefulConceptsAndSTL/5b-TP.ipynb)\n",
"* [Smart pointers](/notebooks/5-UsefulConceptsAndSTL/6-SmartPointers.ipynb)\n",
" * [TP 16](/notebooks/5-UsefulConceptsAndSTL/6b-TP.ipynb)\n",
" * [TP 17](/notebooks/5-UsefulConceptsAndSTL/6b-TP.ipynb)\n",
"* [Algorithms](/notebooks/5-UsefulConceptsAndSTL/7-Algorithms.ipynb)\n"
]
},
......
......@@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Getting started in C++](/) - [Useful concepts and STL](/notebooks/5-UsefulConceptsAndSTL/0-main.ipynb) - [TP 13](/notebooks/5-UsefulConceptsAndSTL/1b-TP.ipynb)"
"# [Getting started in C++](/) - [Useful concepts and STL](/notebooks/5-UsefulConceptsAndSTL/0-main.ipynb) - [TP 14](/notebooks/5-UsefulConceptsAndSTL/1b-TP.ipynb)"
]
},
{
......@@ -14,7 +14,7 @@
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span></li><li><span><a href=\"#EXERCICE-45:-replace-error-function-by-an-Error-exception\" data-toc-modified-id=\"EXERCICE-45:-replace-error-function-by-an-Error-exception-2\">EXERCICE 45: replace <code>error</code> function by an <code>Error</code> exception</a></span></li><li><span><a href=\"#EXERCICE-46:-better-error-handling-of-overflow\" data-toc-modified-id=\"EXERCICE-46:-better-error-handling-of-overflow-3\">EXERCICE 46: better error handling of overflow</a></span></li></ul></div>"
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Introduction\" data-toc-modified-id=\"Introduction-1\">Introduction</a></span></li><li><span><a href=\"#EXERCICE-35:-replace-error-function-by-an-Error-exception\" data-toc-modified-id=\"EXERCICE-35:-replace-error-function-by-an-Error-exception-2\">EXERCICE 35: replace <code>error</code> function by an <code>Error</code> exception</a></span></li><li><span><a href=\"#EXERCICE-36:-proper-handling-of-overflow\" data-toc-modified-id=\"EXERCICE-36:-proper-handling-of-overflow-3\">EXERCICE 36: proper handling of overflow</a></span></li><li><span><a href=\"#[optional]-EXERCICE-37:-char-case\" data-toc-modified-id=\"[optional]-EXERCICE-37:-char-case-4\">[optional] EXERCICE 37: <code>char</code> case</a></span></li><li><span><a href=\"#[optional]-EXERCICE-38:-negative-case\" data-toc-modified-id=\"[optional]-EXERCICE-38:-negative-case-5\">[optional] EXERCICE 38: negative case</a></span></li></ul></div>"
]
},
{
......@@ -23,129 +23,141 @@
"source": [
"### Introduction\n",
"\n",
"[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP.\n",
"\n",
"We will start from the solution to exercice 36 of the procedural object TP. `initial_file.cpp` in the TP directory is a copy to the solution of this exercice (symbolic link wouldn't have worked with Docker)."
"[This notebook](/notebooks/TP/HowTo.ipynb) explains very briefly your options to run the TP."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 45: replace `error` function by an `Error` exception\n",
"### EXERCICE 35: replace `error` function by an `Error` exception\n",
"\n",
"This exception class will:\n",
"\n",
"- Take as argument a `std::string` explaining the exception (to be translated into the `what()` virtual method).\n",
"- Derives from `std::exception`.\n",
"\n",
"New `main()` function is:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"// Not usable in Xeus-cling\n",
"\n",
"int main(int argc, char** argv)\n",
"{\n",
" static_cast<void>(argc); // to silence warning about unused argc - don't bother \n",
" static_cast<void>(argv); // to silence warning about unused argv - don't bother \n",
" \n",
" try\n",
" {\n",
" {\n",
" TestDisplayContainer<4> container;\n",
" container.Register(new TestDisplayPowerOfTwoApprox065<int>(1000000));\n",
" container.Register(new TestDisplayPowerOfTwoApprox035<int>(1000000));\n",
" container.Register(new TestDisplaySum<int>(1000000));\n",
" container.Register(new TestDisplaySum<short>(1000000)); \n",
" \n",
" loop(4, 16, 4, container);\n",
" }\n",
" \n",
" {\n",
" TestDisplayContainer<2> container;\n",
" container.Register(new TestDisplayPowerOfTwoApprox065<char>(1000));\n",
" container.Register(new TestDisplayPowerOfTwoApprox065<unsigned char>(1000));\n",
" loop(1, 8, 1, container);\n",
" }\n",
" }\n",
" catch(const std::exception& e)\n",
" {\n",
" std::cerr << \"An error occurred in the program: \" << e.what() << std::endl;\n",
" }\n",
"\n",
" return EXIT_SUCCESS;\n",
"}"
"Add a `try/catch` block in the main to properly catch the exceptions.\"\n",
"\n",
"Try it works by introducing a behaviour that should throw (for instance reduce the `TestDisplayContainer` template parameter)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check exceptions are working by reducing one of the integer template parameter."
"### EXERCICE 36: proper handling of overflow\n",
"\n",
"We are now well equiped to deal with the overflow issue we saw earlier. \n",
"\n",
"We would like to print _Overflow!_ in the lines when the chosen number of bits is not compatible with the chosen integer type. Contrary to what we did in previous exercice, we want to recover after such an exception, not to terminate immediately the program.\n",
"\n",
"This [StackOverflow post](https://stackoverflow.com/questions/199333/how-to-detect-unsigned-integer-multiply-overflow) provides an interesting non-standard feature introduced in clang and gcc to deal with this: special functions that tell if an operation will overflow (other replies give hints to do so manually). The functions to use are:\n",
"\n",
"````\n",
"__builtin_add_overflow(T a, T b, T* sum)\n",
"__builtin_mul_overflow(T a, T b, T* product)\n",
"````\n",
"\n",
"where `T` is the type considered; these functions return 0 if no overflow occurs (and result is in this case given in third argument).\n",
"\n",
"With this:\n",
"\n",
"* Replace `long` by `int` to make the issues reappear.\n",
"* Use the two functions above to identify when an overflow occur. There are three such checks to add (even if only two plays out with the `int` case).\n",
"* Define a `void TestDisplay::PrintOverflow(int Nbits, const Error& e) const` method that will provide the print when an overflow occurs. This method will be used in the `catch` blocks for each line.\n",
"\n",
"_Expected results:_\n",
"\n",
"````\n",
" [Width 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 3846154/100000000]\n",
" [Width 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 240385/100000000]\n",
" [Width 12 bits]: 0.65 ~ 0.649902 (2662/2^12) [error = 15024/100000000]\n",
" [Width 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 939/100000000]\n",
" [Width 20 bits]: 0.65 ~ 0.65 (681574/2^20) [error = 59/100000000]\n",
" [Width 24 bits]: 0.65 ~ 0.65 (10905190/2^24) [error = 4/100000000]\n",
" [Width 28 bits]: 0.65 ~ 0.65 (174483046/2^28) [error = 0/100000000]\n",
" [Width 32 bits]: Overflow! (in times_power_of_2())\n",
"\n",
" [Width 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 1785714/100000000]\n",
" [Width 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 111607/100000000]\n",
" [Width 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 6975/100000000]\n",
" [Width 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 436/100000000]\n",
" [Width 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 27/100000000]\n",
" [Width 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 2/100000000]\n",
" [Width 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/100000000]\n",
" [Width 32 bits]: Overflow! (in times_power_of_2())\n",
"\n",
" [Width 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 29917/1000000]\n",
" [Width 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2000/1000000]\n",
" [Width 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 239/1000000]\n",
" [Width 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 239/1000000]\n",
" [Width 20 bits]: Overflow! (in operator*(IntT, const PowerOfTwoApprox<IntT>&))\n",
" [Width 24 bits]: Overflow! (in operator*(IntT, const PowerOfTwoApprox<IntT>&))\n",
" [Width 28 bits]: Overflow! (in operator*(IntT, const PowerOfTwoApprox<IntT>&))\n",
" [Width 32 bits]: Overflow! (in times_power_of_2())\n",
"````"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 46: better error handling of overflow\n",
"\n",
"The way overflows were handled without exception is shaky at best: interface is cumbersome and the `operator*` management is catastrophic.\n",
"### [optional] EXERCICE 37: `char` case\n",
"\n",
"Introduce an `Overflow` exception that should replace it (the `overflow` arguments should all go away with this). We will accept here to lose conditions: we only want to know whether a line could be computed or failed due to an overflow.\n",
"Replace the type `int` by `char` (`char` might be used to represent integers over 1 byte; `unsigned char` also exists)\n",
"\n",
"In the `Display` methods of `TestDisplayXXX` classes:\n",
"You should see gibberish on screen: when printing it doesn't know `char` are used for integers. \n",
"\n",
"* Catch the `Overflow` exceptions.\n",
"* Call a new protected method `PrintOverflow()` which prints the case of an overflow.\n",
"Try to fix it! The idea is to convert `char` and `unsigned char` before printing, but there are many ways to tackle the issue (two different solutions are provided).\n",
"\n",
"Expected output should be:\n",
"* Each time an integer of templated type needs to be printed, address the issue through a template specialization or through a `constexpr`. The solution `exercice37_constexpr` shows such a solution.\n",
"\n",
"````\n",
"[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000]\n",
"[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 2404/1000000]\n",
"[With 12 bits]: 0.65 ~ 0.649902 (2662/2^12) [error = 150/1000000]\n",
"[With 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]\n",
"\n",
"[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/1000000]\n",
"[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 1116/1000000]\n",
"[With 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 70/1000000]\n",
"[With 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]\n",
"\n",
"[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 29930/1000000]\n",
"[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2012/1000000]\n",
"[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 252/1000000]\n",
"[With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 252/1000000]\n",
"\n",
"[With 4 bits]: Overflow! \n",
"[With 8 bits]: Overflow! \n",
"[With 12 bits]: Overflow! \n",
"[With 16 bits]: Overflow! \n",
"\n",
"[With 1 bits]: 0.65 ~ 0.5 (1/2^1) [error = 231/1000]\n",
"[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 154/1000]\n",
"[With 3 bits]: 0.65 ~ 0.625 (5/2^3) [error = 38/1000]\n",
"[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38/1000]\n",
"[With 5 bits]: 0.65 ~ 0.65625 (21/2^5) [error = 10/1000]\n",
"[With 6 bits]: Overflow! \n",
"[With 7 bits]: Overflow! \n",
"[With 8 bits]: Overflow! \n",
"\n",
"[With 1 bits]: 0.65 ~ 0.5 (1/2^1) [error = 231/1000]\n",
"[With 2 bits]: 0.65 ~ 0.75 (3/2^2) [error = 154/1000]\n",
"[With 3 bits]: 0.65 ~ 0.625 (5/2^3) [error = 38/1000]\n",
"[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38/1000]\n",
"[With 5 bits]: 0.65 ~ 0.65625 (21/2^5) [error = 10/1000]\n",
"[With 6 bits]: 0.65 ~ 0.65625 (42/2^6) [error = 10/1000]\n",
"[With 7 bits]: Overflow! \n",
"[With 8 bits]: Overflow! \n",
"````\n"
"* Create a `PrintInt()` struct with a static method which will evaluates the type of T and apply a different treatment depending on result and use it wherever necessary. \n",
"It uses up [std::is_same](https://en.cppreference.com/w/cpp/types/is_same) and [std::conditional](https://en.cppreference.com/w/cpp/types/conditional). `exercice37_struct` solution follows this method with an additional optional spin the make the call easier for end-user."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### [optional] EXERCICE 38: negative case\n",
"\n",
"Negative values don't fare well either: if you try to replace 0.65 by -0.65, you will be underwhelmed...\n",
"\n",
"To handle this properly, you should:\n",
"\n",
"* Add a data atribute in `PowerOfTwoApprox` which will keep the information about the sign.\n",
"* Make the computation on the absolute value of the floating point number, and properly put on the sign whenever necessary.\n",
"\n",
"_Expected result_:\n",
"\n",
" [With 4 bits]: -0.65 ~ -0.625 (-10/2^4) [error = 3846154/100000000]\n",
" [With 8 bits]: -0.65 ~ -0.648438 (-166/2^8) [error = 240385/100000000]\n",
" [With 12 bits]: -0.65 ~ -0.649902 (-2662/2^12) [error = 15024/100000000]\n",
" [With 16 bits]: -0.65 ~ -0.649994 (-42598/2^16) [error = 939/100000000]\n",
" [With 20 bits]: -0.65 ~ -0.65 (-681574/2^20) [error = 59/100000000]\n",
" [With 24 bits]: -0.65 ~ -0.65 (-10905190/2^24) [error = 4/100000000]\n",
" [With 28 bits]: -0.65 ~ -0.65 (-174483046/2^28) [error = 0/100000000]\n",
" [With 32 bits]: -0.65 ~ -0.65 (-2791728742/2^32) [error = 0/100000000]\n",
"\n",
" [With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 1785714/100000000]\n",
" [With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 111607/100000000]\n",
" [With 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 6975/100000000]\n",
" [With 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 436/100000000]\n",
" [With 20 bits]: 0.35 ~ 0.35 (734003/2^21) [error = 27/100000000]\n",
" [With 24 bits]: 0.35 ~ 0.35 (11744051/2^25) [error = 2/100000000]\n",
" [With 28 bits]: 0.35 ~ 0.35 (187904819/2^29) [error = 0/100000000]\n",
" [With 32 bits]: 0.35 ~ 0.35 (3006477107/2^33) [error = 0/100000000]\n",
"\n",
" [With 4 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -535 [error = 98644/1000000]\n",
" [With 8 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -590 [error = 5981/1000000]\n",
" [With 12 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]\n",
" [With 16 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]\n",
" [With 20 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]\n",
" [With 24 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]\n",
" [With 28 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]\n",
" [With 32 bits]: -0.65 * 3515 + 0.35 * 4832 = -594 ~ -593 [error = 927/1000000]"
]
},
{
......
......@@ -14,18 +14,24 @@
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-47:-Use-std::vector-to-store-the-test_display_list_-data\" data-toc-modified-id=\"EXERCICE-47:-Use-std::vector-to-store-the-test_display_list_-data-1\">EXERCICE 47: Use <code>std::vector</code> to store the <code>test_display_list_</code> data</a></span></li></ul></div>"
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-39:-Use-std::vector-to-store-the-TestDisplayContainer::test_display_list_-data\" data-toc-modified-id=\"EXERCICE-39:-Use-std::vector-to-store-the-TestDisplayContainer::test_display_list_-data-1\">EXERCICE 39: Use <code>std::vector</code> to store the <code>TestDisplayContainer::test_display_list_</code> data</a></span></li></ul></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 47: Use `std::vector` to store the `test_display_list_` data\n",
"### EXERCICE 39: Use `std::vector` to store the `TestDisplayContainer::test_display_list_` data\n",
"\n",
"Replace the tedious double pointer by a `std::vector<TestDisplay*>`.\n",
"\n",
"**NOTE**: warnings will appear due to types: `std::vector` expects `std::size_t` rather than `int` for its indexes for instance. Fix them!"
"Remove the template argument of `TestDisplayContainer`: we will now use `push_back()` to add any new element registered.\n",
"\n",
"The interface of the class which be lightened:\n",
"\n",
"* `GetCapacity()` and `current_position_` are no longer required.\n",
"* `GetSize()` implementation should just call the `size_` method of the underlying `std::vector` object.\n",
"* In `operator[]`, the check about `nullptr` is not required any longer; a simple `assert` in the `Register()` method is more than enough.\n"
]
},
{
......
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Getting started in C++](/) - [Useful concepts and STL](/notebooks/5-UsefulConceptsAndSTL/0-main.ipynb) - [TP 15](/notebooks/5-UsefulConceptsAndSTL/5b-TP.ipynb)"
]
},
{
"cell_type": "markdown",
"metadata": {
"toc": true
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-48:-Use-move-semantic-for-std::string-arguments\" data-toc-modified-id=\"EXERCICE-48:-Use-move-semantic-for-std::string-arguments-1\">EXERCICE 48: Use move semantic for <code>std::string</code> arguments</a></span></li></ul></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 48: Use move semantic for `std::string` arguments\n",
"\n",
"In `Error` constructor and `PrintNumericalError()` function.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"© _CNRS 2016_ - _Inria 2018-2019_ \n",
"_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_ \n",
"_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "C++17",
"language": "C++17",
"name": "xeus-cling-cpp17"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".cpp",
"mimetype": "text/x-c++src",
"name": "c++",
"version": "-std=c++17"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
"autoclose": false,
"autocomplete": true,
"bibliofile": "biblio.bib",
"cite_by": "apalike",
"current_citInitial": 1,
"eqLabelWithNumbers": true,
"eqNumInitial": 1,
"hotkeys": {
"equation": "Ctrl-E",
"itemize": "Ctrl-I"
},
"labels_anchors": false,
"latex_user_defs": false,
"report_style_numbering": false,
"user_envs_cfg": false
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": true,
"skip_h1_title": true,
"title_cell": "Table of contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
}
},
"nbformat": 4,
"nbformat_minor": 2
}
......@@ -14,14 +14,14 @@
},
"source": [
"<h1>Table of contents<span class=\"tocSkip\"></span></h1>\n",
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-49:-Use-a-shared-pointer-in-the-TestDisplayContainer::test_display_list_-container\" data-toc-modified-id=\"EXERCICE-49:-Use-a-shared-pointer-in-the-TestDisplayContainer::test_display_list_-container-1\">EXERCICE 49: Use a shared pointer in the <code>TestDisplayContainer::test_display_list_</code> container</a></span></li><li><span><a href=\"#EXERCICE-50:-Replace-shared_ptr-by-unique_ptr-for--TestDisplayContainer::test_display_list_\" data-toc-modified-id=\"EXERCICE-50:-Replace-shared_ptr-by-unique_ptr-for--TestDisplayContainer::test_display_list_-2\">EXERCICE 50: Replace <code>shared_ptr</code> by <code>unique_ptr</code> for <code>TestDisplayContainer::test_display_list_</code></a></span></li><li><span><a href=\"#EXERCICE-51:-remove-TestDisplayContainer-class\" data-toc-modified-id=\"EXERCICE-51:-remove-TestDisplayContainer-class-3\">EXERCICE 51: remove <code>TestDisplayContainer</code> class</a></span></li></ul></div>"
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#EXERCICE-40:-Use-a-shared-pointer-in-the-TestDisplayContainer::test_display_list_-container\" data-toc-modified-id=\"EXERCICE-40:-Use-a-shared-pointer-in-the-TestDisplayContainer::test_display_list_-container-1\">EXERCICE 40: Use a shared pointer in the <code>TestDisplayContainer::test_display_list_</code> container</a></span></li><li><span><a href=\"#EXERCICE-41:-Replace-shared_ptr-by-unique_ptr-for--TestDisplayContainer::test_display_list_\" data-toc-modified-id=\"EXERCICE-41:-Replace-shared_ptr-by-unique_ptr-for--TestDisplayContainer::test_display_list_-2\">EXERCICE 41: Replace <code>shared_ptr</code> by <code>unique_ptr</code> for <code>TestDisplayContainer::test_display_list_</code></a></span></li><li><span><a href=\"#EXERCICE-42:-remove-TestDisplayContainer-class\" data-toc-modified-id=\"EXERCICE-42:-remove-TestDisplayContainer-class-3\">EXERCICE 42: remove <code>TestDisplayContainer</code> class</a></span></li></ul></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 49: Use a shared pointer in the `TestDisplayContainer::test_display_list_` container\n",
"### EXERCICE 40: Use a shared pointer in the `TestDisplayContainer::test_display_list_` container\n",
"\n",
"`Register` and `main` function will of course have to be adapted accordingly."
]
......@@ -30,20 +30,24 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 50: Replace `shared_ptr` by `unique_ptr` for `TestDisplayContainer::test_display_list_`\n",
"### EXERCICE 41: Replace `shared_ptr` by `unique_ptr` for `TestDisplayContainer::test_display_list_`\n",
"\n",
"`shared_ptr` was easier to introduce first due to its easier copy mechanism, but is actually unnecessary: `unique_ptr` may provide the same service with more efficiency.\n",
"\n",
"Replace `shared_ptr` by `unique_ptr`; you will need to play a bit with move semantics for that."
"Replace `shared_ptr` by `unique_ptr`; you will need to play a bit with move semantics for that.\n",
"\n",
"To add a _rvalue_ to a `std::vector`, you should use `emplace_back()` method which does almost the same as `push_back()` but is more optimized for move semantics."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EXERCICE 51: remove `TestDisplayContainer` class \n",
"### EXERCICE 42: remove `TestDisplayContainer` class \n",
"\n",
"If you look closely at your current `TestDisplayContainer`, you should realize it is nothing more than a thin wrapper over its internal `std::vector`. Remove the class entirely and replace it by a `std::vector<str::unique_ptr<TestDisplay>>` (you may if you wish create an alias to this type), that might even be named... `TestDisplayContainer`).\n",
"\n",
"The class is now just a wrapper over the underlying `std::vector<std::unique_ptr<TestDisplay>>`, use it directly.\n"
"Consider optimizing `loop()` function with new `for` syntax."
]
},
{
......
cmake_minimum_required(VERSION 3.9)
# Add a compiler flag only if it is accepted.
# This macro is usually defined once and for all in a specific file which is included in the CMakeLists.txt in which
# you need it.
include(CheckCXXCompilerFlag)
macro(add_cxx_compiler_flag _flag)
string(REPLACE "-" "_" _flag_var ${_flag})
check_cxx_compiler_flag("${_flag}" CXX_COMPILER_${_flag_var}_OK)
include(../../cmake/Settings.cmake)
if(CXX_COMPILER_${_flag_var}_OK)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_flag}")
endif()
endmacro()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Debug' as none was specified.")
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
set(CMAKE_CXX_COMPILER clang++ CACHE STRING "C++ compiler")
set(CMAKE_C_COMPILER clang CACHE STRING "C compiler")
set(CMAKE_CXX_STANDARD 17 CACHE INTEGER "Version of the C++ standard to use")
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "If ON the GNU version of the standard is used.")
project(GettingStartedWithModernCpp_TP_Concepts_STL)
add_cxx_compiler_flag("-Weverything") # all warnings for clang
add_cxx_compiler_flag("-Wall") # for gcc (and recognized by clang)
add_cxx_compiler_flag("-Wextra") # for gcc (and recognized by clang)
add_cxx_compiler_flag("-Wconversion")# for gcc
add_cxx_compiler_flag("-Wno-c++98-compat") # We assume we are using modern C++
add_cxx_compiler_flag("-Wno-c++98-compat-pedantic") # We assume we are using modern C++
add_cxx_compiler_flag("-Wno-padded")
project(GettingStartedWithModernCpp_TP_ConceptSTL)
include(../../cmake/AfterProjectSettings.cmake)
add_executable(initial initial_file.cpp)
# add_executable(exercice45 exercice45.cpp)
# add_executable(exercice46 exercice46.cpp)
# add_executable(exercice47 exercice47.cpp)
# add_executable(exercice48 exercice48.cpp)
# add_executable(exercice49 exercice49.cpp)
# add_executable(exercice50 exercice50.cpp)
# add_executable(exercice51 exercice51.cpp)
\ No newline at end of file
add_executable(exercice35 exercice35.cpp)
add_executable(exercice36 exercice36.cpp)
add_executable(exercice37_struct exercice37_struct.cpp)
add_executable(exercice37_constexpr exercice37_constexpr.cpp)
add_executable(exercice38 exercice38.cpp)
add_executable(exercice39 exercice39.cpp)
add_executable(exercice40 exercice40.cpp)
add_executable(exercice41 exercice41.cpp)
add_executable(exercice42 exercice42.cpp)
\ No newline at end of file
This diff is collapsed.
#include <iostream>
#include <sstream> // for std::ostringstream
#include <string>
#include <cmath> // for std::round
#include <algorithm>
#include <cassert>
#include <vector>
//! I create here a new struct in charge of doing once and for all the conversion.
template<class IntT>
struct PrintIntHelper
{
//! std::conditional_t is really close to the ternary operator except that it applies to types.
using return_type = std::conditional_t
<
std::is_same<IntT, char>() || std::is_same<IntT, unsigned char>(),
int,
IntT
>;
static return_type Do(IntT value)
{
return static_cast<return_type>(value);
}
};
// From C++ 14 onward
// The function wasn't mandatory per se but allows to a more user-friendly interface:
// PrintInt(value);
// rather than
// PrintIntHelper<IntT>::Do(value);
template<class T>
auto PrintInt(T value)
{
return PrintIntHelper<T>::Do(value);
}
class Error : public std::exception
{
public:
//! Constructor.
Error(const std::string& message);
//! Overrides what method.
virtual const char* what() const noexcept override;
private:
const std::string message_;
};
Error::Error(const std::string& message)
: message_(message)
{ }
const char* Error::what() const noexcept
{
return message_.c_str();
}
//! Returns `number` * (2 ^ `exponent`)
template<class IntT>
IntT times_power_of_2(IntT number, int exponent)
{
constexpr IntT one = static_cast<IntT>(1);
constexpr IntT two = static_cast<IntT>(2);
IntT sign = one;
if (number < 0)
{
sign = -one;
number = -number;
};
while (exponent > 0)
{
IntT product;
if (__builtin_mul_overflow(number, two, &product))
{
std::cout << "OVERFLOW for number " << number << std::endl;
throw Error("Overflow! (in times_power_of_2())");
}
number = product;