{"cells":[{"cell_type":"markdown","metadata":{"id":"9xoK4OIjIfZA"},"source":["#計算機程式設計二\n","#第十七週上課內容\n","## C++ 17 and C++ 20\n","\n","### 關於 C++17, c++20 的一些補充說明\n","\n","用 wandbox online c++ compiler 來測試 c++17 和 c++20 的新功能：https://wandbox.org/\n","\n"]},{"cell_type":"markdown","source":["\n","### `std::optional`\n","\n","```c++\n","#include <optional>\n","#include <iostream>\n","#include <vector>\n","#include <string>\n","using namespace std;\n","\n","optional<string> getFirst(const vector<string>& vec){\n","  if ( !vec.empty() ) return optional<string>(vec[0]);\n","  else return nullopt;\n","}\n","\n","ostream& operator<<(ostream& os, optional<string> opt)\n","{\n","  return os << opt.value_or(\"Nobody\");\n","}\n","\n","int main()\n","{  \n","  vector<string> vec{\"Alice\",\"Bob\",\"Carl\"};\n","  vector<string> empty_vec;\n","    \n","  auto str1 = getFirst(vec);\n","  auto str2 = getFirst(empty_vec);\n","  auto str3 = getFirst({\"Alice\", \"Daniel\"});\n","    \n","  cout << \"str1: \" << str1 << endl;     \n","  cout << \"str2: \" << str2 << endl;\n","\n","  cout << ((str1==str2) ? \"equal\" : \"different\") << endl;\n","  cout << ((str1==str3) ? \"equal\" : \"different\") << endl;\n","}\n","```\n","\n","這是參考 functional programming language 而新加入的 class。例如在 Haskell 裡面有 `Maybe` \n","\n","```haskell\n","data Maybe a = Just a | Nothing\n","```\n","\n","```haskell\n","f::Int -> Maybe Int \n","f 0 = Nothing \n","f x = Just x\n","```\n","\n","可以用來處理沒有「值」的情況，這樣就可以繼續當成一般的物件使用，可以若無其事地拿來比較或是顯示。\n","\n","編譯時要記得指定 std  ` g++ -std=c++17`\n","\n","參考：http://en.cppreference.com/w/cpp/utility/optional\n","\n","\n","\n"],"metadata":{"id":"knm-TENG3IYH"}},{"cell_type":"code","source":["%%writefile optional.cpp\n","#include <optional>\n","#include <iostream>\n","#include <vector>\n","#include <string>\n","using namespace std;\n","\n","optional<string> getFirst(const vector<string>& vec){\n","  if ( !vec.empty() ) return optional<string>(vec[0]);\n","  else return nullopt;\n","}\n","\n","ostream& operator<<(ostream& os, optional<string> opt)\n","{\n","  return os << opt.value_or(\"Nobody\");\n","}\n","\n","int main()\n","{  \n","  vector<string> vec{\"Alice\",\"Bob\",\"Carl\"};\n","  vector<string> empty_vec;\n","    \n","  auto str1 = getFirst(vec);\n","  auto str2 = getFirst(empty_vec);\n","  auto str3 = getFirst({\"Alice\", \"Daniel\"});\n","    \n","  cout << \"str1: \" << str1 << endl;     \n","  cout << \"str2: \" << str2 << endl;\n","\n","  cout << ((str1==str2) ? \"equal\" : \"different\") << endl;\n","  cout << ((str1==str3) ? \"equal\" : \"different\") << endl;\n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"ELG_prxaLqbq","executionInfo":{"status":"ok","timestamp":1672743070680,"user_tz":-480,"elapsed":309,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"108d5e02-f265-4d42-fe67-d048817ccc98"},"execution_count":32,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting optional.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ optional.cpp -o optional -std=c++17\n","./optional\n","\n"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"CSBLdXlXN34a","executionInfo":{"status":"ok","timestamp":1672743078142,"user_tz":-480,"elapsed":2267,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"8bc621e9-ef71-4448-a340-30dd322efea8"},"execution_count":33,"outputs":[{"output_type":"stream","name":"stdout","text":["str1: Alice\n","str2: Nobody\n","different\n","equal\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":33}]},{"cell_type":"markdown","source":["\n","\n","### `std::variant`\n","\n","需要 `#include<variant>`\n","\n","```c++\n","#include <variant>\n","#include <iostream>\n","int main()\n","{\n","  std::variant<std::string, int> v{\"abc\"};\n","  std::cout << std::get<0>(v) << std::endl;\n","  std::cout << std::get<std::string>(v) << std::endl;\n","  v = 3;\n","  std::cout << std::get<1>(v) << std::endl;\n","  std::cout << std::get<int>(v) << std::endl;\n","  std::visit([](const auto& x) {std::cout << x << std::endl; }, v);\n","}\n","```\n","\n","允許\t`v` 裡面放 `int` 或是 `string`\n","\n"],"metadata":{"id":"E5BTzs4lx2_a"}},{"cell_type":"code","source":["%%writefile variant.cpp\n","#include <variant>\n","#include <iostream>\n","int main()\n","{\n","  std::variant<std::string, int> v{\"abc\"};\n","  std::cout << std::get<0>(v) << std::endl;\n","  std::cout << std::get<std::string>(v) << std::endl;\n","  v = 3;\n","  std::cout << std::get<1>(v) << std::endl;\n","  std::cout << std::get<int>(v) << std::endl;\n","  std::visit([](const auto& x) {std::cout << x << std::endl; }, v);\n","}\n"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"-e8ZHDU4ZzdL","executionInfo":{"status":"ok","timestamp":1672743371551,"user_tz":-480,"elapsed":327,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"8538c092-9c49-439f-edfe-1a30228c1aff"},"execution_count":34,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting variant.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ variant.cpp -o variant -std=c++17\n","./variant"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"eouw4encWqlo","executionInfo":{"status":"ok","timestamp":1672743378833,"user_tz":-480,"elapsed":1086,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"221ca3ab-bc3a-4432-e2e5-9a9c92a89e67"},"execution_count":35,"outputs":[{"output_type":"stream","name":"stdout","text":["abc\n","abc\n","3\n","3\n","3\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":35}]},{"cell_type":"markdown","source":["\n","### Structured Binding Declaration\n","\n","```c++\n","#include <iostream>\n","#include <string>\n","#include <tuple>\n","using namespace std;\n","\n","int main()\n","{\n","  int a[2] = {1,2};\n","\n","  auto [b,c] = a;\n","  auto& [br, cr] = a; \n","\n","  cout << b << \" \" << c << endl;\n","  cout << br << \" \" << cr << endl;\n","\n","  float x{2.5};\n","  string  y{\"Steve\"};\n","  int   z{6};\n","\n","  tuple<float&,string&&,int> tp(x, std::move(y), z);\n","  const auto& [u,v,w] = tp;\n","  cout << u << \" \" << v << \" \" << w << endl;\n","\n","  struct S {\n","\tint x; \n","\tdouble y;\n","  };\n","  S s{6, 6.6};\n","\n","  S s2 =[](auto ss){auto [x, y] = ss; return S{x+1, y*2};}(s);\n","  [](auto ss){auto [x, y] = ss; cout<<x<<\" \"<<y<<endl;}(s2);\n","}\n","```\n","\n","類似其他高階語言常有的語法，例如 Python：\n","\n","```python\n","a = (1,2,3)\n","x, y, z = a\n","```\n","\n","在 C++17，對於 array 或是 tuple，可以在等號右邊，把每個元素拆開來，分別設定給不同的變數。\n","\n","參考： http://en.cppreference.com/w/cpp/language/structured_binding\n","\n"],"metadata":{"id":"o53eZrMd36lZ"}},{"cell_type":"code","source":["%%writefile structured.cpp\n","#include <iostream>\n","#include <string>\n","#include <tuple>\n","using namespace std;\n","\n","int main()\n","{\n","  int a[] = {1, 2, 3, 4};\n","\n","  auto [b, c, d, e] = a;\n","  auto& [br, cr, dr, er] = a; \n","\n","  cout << b << \" \" << c << endl;\n","  cout << br << \" \" << cr << endl;\n","\n","  br = 10;\n","  cr = 100;\n","\n","  for (auto v : a) {\n","    cout << v << \" \";\n","  }\n","  cout << \"\\n\";\n","\n","  float x{2.5};\n","  string  y{\"Steve\"};\n","  int   z{6};\n","\n","  tuple<float&,string&&,int> tp(x, std::move(y), z);\n","  const auto& [u,v,w] = tp;\n","  cout << u << \" \" << v << \" \" << w << endl;\n","  cout << x << \"\\n\";\n","  u = 3.5;\n","  cout << x << \"\\n\";\n","  \n","  struct S {\n","\t  int x; \n","\t  double y;\n","  };\n","  S s{6, 6.6};\n","\n","  S s2 =[](auto ss){auto [x, y] = ss; return S{x+1, y*2};}(s);\n","  [](auto ss){auto [x, y] = ss; cout<<x<<\" \"<<y<<endl;}(s2);\n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"PbZFmxROydSE","executionInfo":{"status":"ok","timestamp":1672744118319,"user_tz":-480,"elapsed":352,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"e511d491-d582-4ca7-f619-b5d53d3e0316"},"execution_count":50,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting structured.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ structured.cpp -o structured -std=c++17\n","./structured"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"51EzAJd9yxSE","executionInfo":{"status":"ok","timestamp":1672744123330,"user_tz":-480,"elapsed":812,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"30e9aa20-1641-4a81-ca00-7f57ccff3c5c"},"execution_count":51,"outputs":[{"output_type":"stream","name":"stdout","text":["1 2\n","1 2\n","10 100 3 4 \n","2.5 Steve 6\n","2.5\n","3.5\n","7 13.2\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":51}]},{"cell_type":"markdown","source":["\n","### If Statement with Initializer\n","\n","```c++\n","#include <iostream>\n","#include <string>\n","\n","using namespace std;\n","int main()\n","{\n","  const string str = \"Hello World!\";\n","\n","  auto it = str.find(\"Hello\");\n","  if (it != string::npos)\n","\tcout << \"Hi\\n\";\n","  \n","  // old\n","  {\n","\tauto it = str.find(\"Hello\");\n","\tif (it != string::npos)\n","\t  cout << \"Hi\\n\";\n","  }\n","\n","  // new\n","  if (const auto it = str.find(\"Hello\"); it != string::npos)\n","\tcout << \" Hi\\n\";\n","}\n","```\n","\n","在 if 的條件判斷區域裡面設定初值，類似 for 的語法。\n"],"metadata":{"id":"5Rxn3Yp23B22"}},{"cell_type":"code","source":["%%writefile if_init.cpp\n","#include <iostream>\n","#include <string>\n","\n","using namespace std;\n","int main()\n","{\n","  const string str = \"Hello World!\";\n","\n","  auto it1 = str.find(\"Hello\");\n","  if (it1 != string::npos)\n","\tcout << \"Hi\\n\";\n","  \n","  \n","  // old\n","  {\n","\tauto it2 = str.find(\"Hello\");\n","\tif (it2 != string::npos)\n","\t  cout << \"Hi\\n\";\n","  }\n","\n","  // new\n","  if (const auto it3 = str.find(\"Hello\"); it3 != string::npos)\n","\tcout << \" Hi\\n\";\n","\n","\n","}\n"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"MvEW_GLE2VDW","executionInfo":{"status":"ok","timestamp":1672744830977,"user_tz":-480,"elapsed":313,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"6d0dd66e-a587-4a2c-bb93-dc6dd6ee7863"},"execution_count":60,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting if_init.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++ if_init.cpp -o if_init -std=c++17\n","./if_init"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"HJ7UNHP82cJl","executionInfo":{"status":"ok","timestamp":1672744838771,"user_tz":-480,"elapsed":1015,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"a63579a4-5b29-4fd6-b9d2-b4f429664d2e"},"execution_count":61,"outputs":[{"output_type":"stream","name":"stdout","text":["\u001b[01m\u001b[Kif_init.cpp:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Kint main()\u001b[m\u001b[K’:\n","\u001b[01m\u001b[Kif_init.cpp:26:11:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[K‘\u001b[01m\u001b[Kit3\u001b[m\u001b[K’ was not declared in this scope\n","   cout << \u001b[01;31m\u001b[Kit3\u001b[m\u001b[K << \"\\n\";\n","           \u001b[01;31m\u001b[K^~~\u001b[m\u001b[K\n","\u001b[01m\u001b[Kif_init.cpp:26:11:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Ksuggested alternative: ‘\u001b[01m\u001b[Kit1\u001b[m\u001b[K’\n","   cout << \u001b[01;36m\u001b[Kit3\u001b[m\u001b[K << \"\\n\";\n","           \u001b[01;36m\u001b[K^~~\u001b[m\u001b[K\n","           \u001b[32m\u001b[Kit1\u001b[m\u001b[K\n","Hi\n","0\n","Hi\n"," Hi\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":61}]},{"cell_type":"markdown","source":["## Install g++-10, which supports C++ 20 standard"],"metadata":{"id":"1DTZksF0XntO"}},{"cell_type":"code","source":["%%shell\n","sudo add-apt-repository ppa:ubuntu-toolchain-r/test\n","sudo apt-get update\n","sudo apt install gcc-10 gcc-10-base gcc-10-doc g++-10\n","sudo apt install libstdc++-10-dev libstdc++-10-doc "],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"JuOf9cuw9rKw","executionInfo":{"status":"ok","timestamp":1672745753090,"user_tz":-480,"elapsed":24441,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"4c1e7e97-5849-47fc-9a34-e52cfb0c037e"},"execution_count":70,"outputs":[{"output_type":"stream","name":"stdout","text":[" Toolchain test builds; see https://wiki.ubuntu.com/ToolChain\n","\n"," More info: https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test\n","Press [ENTER] to continue or Ctrl-c to cancel adding it.\n","\n","Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]\n","Hit:2 http://archive.ubuntu.com/ubuntu bionic InRelease\n","Get:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]\n","Hit:4 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease\n","Ign:5 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease\n","Hit:6 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease\n","Hit:7 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release\n","Hit:8 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease\n","Get:9 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [83.3 kB]\n","Hit:10 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease\n","Hit:11 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease\n","Hit:13 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease\n","Hit:14 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic InRelease\n","Fetched 261 kB in 1s (204 kB/s)\n","Reading package lists... Done\n","Hit:1 http://security.ubuntu.com/ubuntu bionic-security InRelease\n","Hit:2 http://archive.ubuntu.com/ubuntu bionic InRelease\n","Hit:3 http://archive.ubuntu.com/ubuntu bionic-updates InRelease\n","Hit:4 http://archive.ubuntu.com/ubuntu bionic-backports InRelease\n","Hit:5 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease\n","Ign:6 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  InRelease\n","Hit:7 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease\n","Hit:8 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64  InRelease\n","Hit:9 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64  Release\n","Hit:10 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease\n","Hit:11 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease\n","Hit:12 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease\n","Hit:14 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic InRelease\n","Reading package lists... Done\n","Reading package lists... Done\n","Building dependency tree       \n","Reading state information... Done\n","g++-10 is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","gcc-10 is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","gcc-10-base is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","gcc-10-doc is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","The following package was automatically installed and is no longer required:\n","  libnvidia-common-460\n","Use 'sudo apt autoremove' to remove it.\n","0 upgraded, 0 newly installed, 0 to remove and 24 not upgraded.\n","Reading package lists... Done\n","Building dependency tree       \n","Reading state information... Done\n","libstdc++-10-dev is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","libstdc++-10-doc is already the newest version (10.3.0-1ubuntu1~18.04~1).\n","The following package was automatically installed and is no longer required:\n","  libnvidia-common-460\n","Use 'sudo apt autoremove' to remove it.\n","0 upgraded, 0 newly installed, 0 to remove and 24 not upgraded.\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":70}]},{"cell_type":"markdown","source":["\n","### `for_each_n`\n","\n","```c++\n","#include <iostream>\n","#include <algorithm>\n","#include <vector>\n","#include <string>\n","using namespace std;\n","int main()\n","{\n","  vector<string> ns{\"Alice\", \"Bob\", \"Carl\", \"Dora\", \"Eddie\"};\n","  for (auto& n: ns) cout << n << \", \";\n","  cout << endl;\n","  for_each_n(ns.begin(), 3, [](auto& n){ n = n+\" Marley\"; });\n","  for (auto& n: ns) cout << n << \", \";\n","  cout << endl;\n","}\n","```\n","\n","參考來源：http://en.cppreference.com/w/cpp/algorithm/for_each_n\n","\n","在迴圈中只取出 `n` 個元素做運算。"],"metadata":{"id":"fSGgn9Lz4Hsw"}},{"cell_type":"code","source":["%%writefile foreachn.cpp\n","#include <iostream>\n","#include <algorithm>\n","#include <vector>\n","#include <string>\n","using namespace std;\n","int main()\n","{\n","  vector<string> ns{\"Alice\", \"Bob\", \"Carl\", \"Dora\", \"Eddie\"};\n","  for (auto& n: ns) cout << n << \", \";\n","  cout << endl;\n","  for_each_n(ns.begin(), 3, [](auto& n){ n = n+\" Marley\"; });\n","  for (auto& n: ns) cout << n << \", \";\n","  cout << endl;\n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"dGq7dNs6Z2Zg","executionInfo":{"status":"ok","timestamp":1672745706684,"user_tz":-480,"elapsed":281,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"1374c5c9-02a4-4d91-af08-2d3bedff8cbf"},"execution_count":68,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting foreachn.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++-10 foreachn.cpp -o foreachn -std=c++20\n","./foreachn"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"GYEpLsOTaDdp","executionInfo":{"status":"ok","timestamp":1672745771456,"user_tz":-480,"elapsed":2038,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"c64f5672-4e56-4d1e-c8b1-af8b51cd80d1"},"execution_count":72,"outputs":[{"output_type":"stream","name":"stdout","text":["Alice, Bob, Carl, Dora, Eddie, \n","Alice Marley, Bob Marley, Carl Marley, Dora, Eddie, \n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":72}]},{"cell_type":"markdown","source":["\n","### Fold Expression\n","\n","```c++\n","   +\n","  /  \\\n","1     +\n","     /  \\ \n","    2    +\n","       /   \\\n","      3      ...\n","```\n","\n","right fold: 1 + (2 + (3 + (4 + 5)))\n","\n","\n","```c++\n","          +\n","         / \\\n","        +\n","       / \\\n","      +   3\n","     / \\\n","    1  2    \n","```\n","left fold: (((1 + 2) + 3) + 4) + 5\n","\n","unary left fold\n","`(... op pack)`\t\n","展開成 \n","`((pack1 op pack2) op ...) op packN`\n","\n","binary left fold\n","`(init op ... op pack)`\t\n","展開成 \n","`(((init op pack1) op pack2) op ...) op packN`\n","\n","\n","\n","unary right fold\n","`(pack op ...)`\n","展開成\n","`pack1 op (... op (packN-1 op packN))`\n","\n","binary right fold\n","`(pack op ... op init)`\t\n","展開成\n","`pack1 op (... op (packN-1 op (packN op init)))`\n","\n","```c++\n","#include <iostream>\n","#include <string>\n","#include <vector>\n","\n","using namespace std;\n","\n","template<typename ...Args>\n","bool all(Args... args) \n","{ \n","  return (... && args); // unary left fold \n","}\n","\n","template<typename ...Args> \n","auto sum(Args ...args) \n","{ \n","  return (args + ... + 0); // binary right fold \n","}\n","\n","template<typename ...Args> \n","auto sum2(Args ...args) \n","{ \n","  return (args + ...); // unary right fold\n","}\n","\n","template<typename T, typename... Args>\n","void push_back_vec(std::vector<T>& v, Args&&... args)\n","{\n","  (v.push_back(args), ...); // unary right fold\n","}\n"," \n","int main()\n","{ \n","  bool b = all(true, true, false, true);\n","  // the unary left fold expands as ((true && true) && false) && true;\n","\n","  cout << sum(1, 2, 3, 4, 5, 6, 7) << std::endl;\n","  cout << sum2(1, 2, 3, 4, 5, 6, 7) << std::endl;\n","\n","  std::vector<int> v;\n","  push_back_vec(v, 6, 7, 42, 13);\n","  push_back_vec(v, 1, 2, 4);\n","  for (int i : v) std::cout << i << ' ';\n","  std::cout << std::endl;\n","\n","}\n","/*\n","(... op pack)\t((pack1 op pack2) op ...) op packN\n","(init op ... op pack)\t(((init op pack1) op pack2) op ...) op packN\n","(pack op ...)\tpack1 op (... op (packN-1 op packN))\n","(pack op ... op init)\tpack1 op (... op (packN-1 op (packN op init)))\n","*/\n","```\n","\n"],"metadata":{"id":"T4ZV4Zwr9fnT"}},{"cell_type":"code","source":["%%writefile fold.cpp\n","# include <iostream>\n","# include <string>\n","# include <vector>\n","\n","using namespace std;\n","\n","template<typename ...Args>\n","bool all(Args... args) \n","{ \n","  return (... && args); // unary left fold \n","}\n","\n","template<typename ...Args> \n","auto sum(Args ...args) \n","{ \n","  return (args + ... + 0); // binary right fold \n","}\n","\n","template<typename ...Args> \n","auto sum2(Args ...args) \n","{ \n","  return (args + ...); // unary right fold\n","}\n","\n","template<typename T, typename... Args>\n","void push_back_vec(std::vector<T>& v, Args&&... args)\n","{\n","  (v.push_back(args), ...); // unary right fold\n","}\n","\n","int main()\n","{ \n","  bool b = all(3 > 2, 2 > 1, 3 > 4, 4 > 3);\n","  // the unary left fold expands as ((true && true) && false) && true;\n","  cout << boolalpha << b << std::endl;\n","\n","  cout << sum(1, 2, 3, 4, 5, 6, 7) << std::endl;\n","  cout << sum2(1, 2, 3, 4, 5, 6, 7) << std::endl;\n","\n","  std::vector<int> vv;\n","  push_back_vec(vv, 6, 7, 42, 13);\n","  push_back_vec(vv, 1, 2, 4);\n","  for (int i : vv) std::cout << i << ' ';\n","  std::cout << std::endl;\n","\n","}\n","/*\n","(... op pack)    ((pack1 op pack2) op ...) op packN\n","(init op ... op pack)    (((init op pack1) op pack2) op ...) op packN\n","(pack op ...)    pack1 op (... op (packN-1 op packN))\n","(pack op ... op init)    pack1 op (... op (packN-1 op (packN op init)))\n","*/"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"p8JL7gEFdqYS","executionInfo":{"status":"ok","timestamp":1672746892476,"user_tz":-480,"elapsed":286,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"615a33a8-d2b1-41ed-f96a-314d5bffc39e"},"execution_count":85,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting fold.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++-10 fold.cpp -o fold -std=c++20\n","./fold"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"HGig5kS2duVF","executionInfo":{"status":"ok","timestamp":1672746716683,"user_tz":-480,"elapsed":1132,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"707f44c2-a812-4fdf-a5ce-70d99761b215"},"execution_count":84,"outputs":[{"output_type":"stream","name":"stdout","text":["false\n","28\n","28\n","6 7 42 13 1 2 4 \n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":84}]},{"cell_type":"markdown","source":["### `reduce` `transform_reduce`\n","\n","語法如下：\n","\n","```c++\n","template <class InputIt1, class InputIt2, class T, class BinaryOp1, class BinaryOp2>\n","constexpr T \n","transform_reduce(InputIt1 first1, InputIt1 last1, InputIt2 first2,\n","             T init, BinaryOp1 binary_op1, BinaryOp2 binary_op2);\n","```\n","\n","先對 `InputIt1` 和 `InputIt2` 在範圍 `(first1, last1)` 之間的每一組對應元素，用 `binary_op2` 做運算，運算出來的結果，再用 `binary_op1` 以 `init` 當作運算的初值整合起來。\n","\n","```c++\n","#include <vector>\n","#include <functional>\n","#include <iostream>\n","#include <numeric>\n","\n","using namespace std;\n","int main()\n","{\n","  vector<double> x{1.0, 2.0, 3.0}, y{4.0, 5.0, 6.0};\n"," \n","  auto res = transform_reduce(\n","    x.begin(), x.end(),\n","    y.begin(), 0.0, [](auto a, auto b) { return a+b;}, [](auto a, auto b) {return a*b;});\n","  cout << res << endl;\n","\n","  auto res2 = transform_reduce(\n","    x.begin(), x.end(), 0.0, [](auto a, auto b) { return a+b;}, [](auto a) {return a*a;});\n","  cout << res2 << endl;\n","\n","  auto res3 = reduce(\n","    x.begin(), x.end(), 0.0, [](auto a, auto b) { return a+b;});\n","  cout << res3 << endl;\n","\n","  auto res4 = reduce(x.begin(), x.end(), x[0], [](auto a, auto b) {return (a>b)?a:b;});\n","  cout << res4 << endl;\n","}\n","```\n","\n","參考：https://blog.tartanllama.xyz/accumulate-vs-reduce/\n","\n"],"metadata":{"id":"iVUJLjqN9iQw"}},{"cell_type":"code","source":["%%writefile tr_reduce.cpp\n","# include <vector>\n","# include <functional>\n","# include <iostream>\n","# include <numeric>\n","\n","using namespace std;\n","int main()\n","{\n","  vector<double> x{1.0, 2.0, 3.0}, y{4.0, 5.0, 6.0};\n","\n","  auto res = transform_reduce(\n","    x.begin(), x.end(),\n","    y.begin(), 0.0, [](auto a, auto b) { return a+b;}, [](auto a, auto b) {return a*b;});\n","  cout << res << endl;\n","\n","  auto res2 = transform_reduce(\n","    x.begin(), x.end(), 0.0, [](auto a, auto b) { return a+b;}, [](auto a) {return a*a;});\n","  cout << res2 << endl;\n","\n","  auto res3 = reduce(\n","    x.begin(), x.end(), 0.0, [](auto a, auto b) { return a+b;});\n","  cout << res3 << endl;\n","\n","  auto res4 = reduce(x.begin(), x.end(), x[0], [](auto a, auto b) {return (a>b)?a:b;});\n","  cout << res4 << endl;\n","\n","  auto res5 = accumulate(x.begin(), x.end(), 0.0, [](auto a, auto b) { return a+b;});\n","  cout << res5 << endl;\n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"NMyywwIggQdY","executionInfo":{"status":"ok","timestamp":1672747564557,"user_tz":-480,"elapsed":316,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"09ac5c8e-c356-4c6f-8667-c90009ddb201"},"execution_count":90,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting tr_reduce.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++-10 tr_reduce.cpp -o tr_reduce -std=c++20\n","./tr_reduce"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"eKwSt35Sgki0","executionInfo":{"status":"ok","timestamp":1672747570057,"user_tz":-480,"elapsed":1425,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"7d752361-cb49-4c3f-c93c-1bd1da47f690"},"execution_count":91,"outputs":[{"output_type":"stream","name":"stdout","text":["32\n","14\n","6\n","3\n","6\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":91}]},{"cell_type":"markdown","source":["\n","\n","### Ninety-Nine Problems\n","\n","[99 Problems](https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems)\n","\n","#### Some Examples\n","\n","```c++\n","\n","#include <vector>\n","#include <functional>\n","#include <iostream>\n","#include <iomanip>\n","#include <numeric>\n","#include <algorithm>\n","\n","using namespace std;\n","int main()\n","{\n","  vector<int> x{1,2,3,4,5};\n","\n","  //  Reverse a list.\n","  auto res1 = accumulate(x.rbegin(), x.rend(), vector<int>{}, \n","    [](auto&& a, auto b) {a.push_back(b); return a;});\n","  for (auto v:res1)\n","    cout << v << \" \";\n","  cout << endl;\n","\n","  //  Find out whether a list is a palindrome.\n","  vector<int> y{1,2,3,3,2,1};\n","  auto rev = \n","  [](vector<int>x){\n","    return accumulate(x.rbegin(), x.rend(), vector<int>{},\n","      [](auto&& a, auto b) {a.push_back(b); return a;});\n","  };\n","  for (auto v: rev(y))\n","    cout << v << \" \";\n","  cout << endl;\n","  auto res2 = transform_reduce(y.begin(), y.end(), rev(y).begin(), true, [](auto a, auto b){return a&&b;}, [](auto a, auto b){return a==b;});\n","    \n","  auto res2 = transform_reduce(y.rbegin(), y.rend(), \n","           y.begin(), true, \n","           [](auto a, auto b){return a&&b;}, \n","           [](auto a, auto b){return a==b;});\n","  cout << boolalpha << res2 << endl;\n","\n","  // Eliminate consecutive duplicates of list elements.\n","  vector<int> z{1,1,1,3,3,3,2,2,2,2};\n","  auto compress = \n","  [](vector<int>x){\n","    return accumulate(x.begin(), x.end(), vector<int>{x[0]}, \n","      [](auto&& a, auto b){ \n","        if (a.back()!=b) a.push_back(b); \n","        return a;\n","      });\n","  };\n","  for (auto v: compress(z))\n","    cout << v << \" \";\n","  cout << endl;    \n","}\n","```\n","\n","\n","\n"],"metadata":{"id":"msT-G2g59ssp"}},{"cell_type":"code","source":["%%writefile nnty.cpp\n","#include <vector>\n","#include <functional>\n","#include <iostream>\n","#include <iomanip>\n","#include <numeric>\n","#include <algorithm>\n","using namespace std;\n","\n","int main()\n","{\n","  vector<int> vec{1,2,3,4,5,6,7,8,9};\n","  vector<int> rv = accumulate(vec.rbegin(), vec.rend(),\n","    vector<int>{}, [](auto&& a, auto b) {a.push_back(b); return a;});\n","  for (auto& e: rv)\n","    cout << e << \" \";\n","  cout << \"\\n\";\n","\n","  vector<int> x{\n","}\n"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"3VNUmH5JiU7Z","executionInfo":{"status":"ok","timestamp":1672748210433,"user_tz":-480,"elapsed":365,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"2121c8f8-abb0-4611-ce8c-994135a35a0a"},"execution_count":94,"outputs":[{"output_type":"stream","name":"stdout","text":["Overwriting nnty.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++-10 nnty.cpp -o nnty -std=c++20\n","./nnty"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"HZmao9gejxbr","executionInfo":{"status":"ok","timestamp":1672748212358,"user_tz":-480,"elapsed":1404,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"904c2600-2482-419b-8513-965695328261"},"execution_count":95,"outputs":[{"output_type":"stream","name":"stdout","text":["9 8 7 6 5 4 3 2 1 \n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":95}]},{"cell_type":"markdown","source":["\n","#### `Ranges` Library (C++20)\n","\n","Range factories`iota`,`views` (Lazy evaluation)\n","\n","Range adaptors  `take`, `drop`, `filter`, `transform`, `split`\n","\n","```c++\n","#include <iostream>\n","#include <ranges>\n","#include <vector>\n","#include <cctype>\n","\n","int main() {\n","  std::vector<int> v;      \n","  auto isPrime = [] (int i) {\n","    for (auto x=2; x*x <= i; ++x) {\n","      if (i % x == 0) return false;\n","    }\n","    return true;\n","  };\n","  \n","  for (auto i: std::views::iota(1000000) \n","     | std::views::filter(isPrime)\n","     | std::views::take(10)) v.push_back(i); \n","  for (auto i: v) std::cout << i << ' ';   \n","  std::cout << '\\n';\n","  \n","  auto myAdaptor = std::views::transform([] (int i) { return 2*i*i-1; })\n","  | std::views::filter(isPrime);\n","  std::vector<int> nums{17, 5, 41};\n","  for (auto n: nums | myAdaptor)\n","    std::cout << n << ' ';\n","  std::cout << '\\n';\n","  \n","  std::string str{\"I am the master of my fate; I am the captain of my soul.\"};\n","  std::vector<std::string> words;\n","  for (auto w : str | std::views::split(' ') ) {\n","    std::string s;\n","    for (auto c: w) s.push_back(std::toupper(c));\n","    words.push_back(s);\n","  }\n","  for (auto w : words)\n","    std::cout << '(' << w << ')' << ' ';\n","  std::cout << '\\n';\n","}\n","```\n","\n","\n"],"metadata":{"id":"PuiiGR2f9_A2"}},{"cell_type":"markdown","source":["\n","#### `Concepts` Library (C++20)\n","\n","https://en.cppreference.com/w/cpp/concepts\n","\n","https://oopscenities.net/2020/09/29/c20-concept/\n","\n","```c++\n","#include <concepts>\n","#include <iostream>\n"," \n","template <typename T, typename U = T>\n","concept Sumable =\n","  requires(T a, U b)\n","  {\n","    { a + b };\n","    { b + a };\n","  }\n","  && requires(std::ostream& os, const T& a)\n","  {\n","    { os << a };\n","   };\n"," \n","template <Sumable A, Sumable B>\n","//template <typename A, typename B>\n","void sum_and_print(const A& a, const B& b)\n","{\n","  std::cout << (a + b) << \"\\n\";\n","}\n"," \n","struct N\n","{\n","  int value;\n","   N operator+(const N& n) const\n","   {\n","     return { value + n.value };\n","   }\n","};\n"," \n","std::ostream& operator<<(std::ostream& os, const N& n)\n","{\n","  os << n.value;\n","  return os;\n","}\n"," \n","int main()\n","{\n","    sum_and_print( N{6}, N{7});\n","}\n","\n","```\n","\n"],"metadata":{"id":"zAt4CB_t-IpV"}},{"cell_type":"code","source":["%%writefile concept.cpp\n","#include <concepts>\n","#include <iostream>\n","\n","template <typename T, typename U = T>\n","concept Sumable =\n","  requires(T a, U b)\n","  {\n","    { a + b };\n","    { b + a };\n","  }\n","  && requires(std::ostream& os, const T& a)\n","  {\n","    { os << a };\n","   };\n","\n","template <Sumable A, Sumable B>\n","//template <typename A, typename B>\n","void sum_and_print(const A& a, const B& b)\n","{\n","  std::cout << (a + b) << \"\\n\";\n","}\n","\n","struct N\n","{\n","  int value;\n","   N operator+(const N& n) const\n","   {\n","     return { value + n.value };\n","   }\n","};\n","\n","std::ostream& operator<<(std::ostream& os, const N& n)\n","{\n","  os << n.value;\n","  return os;\n","}\n","\n","int main()\n","{\n","    sum_and_print( N{6}, N{7});\n","}"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"2vvOwU3DW9EU","executionInfo":{"status":"ok","timestamp":1672728029452,"user_tz":-480,"elapsed":275,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"de2ac5c3-461c-4715-b589-b5771836c5c4"},"execution_count":27,"outputs":[{"output_type":"stream","name":"stdout","text":["Writing concept.cpp\n"]}]},{"cell_type":"code","source":["%%shell\n","g++-10 concept.cpp -o concept -std=c++20\n","./concept"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"Jdf7p8okXDJY","executionInfo":{"status":"ok","timestamp":1672728126866,"user_tz":-480,"elapsed":742,"user":{"displayName":"HT Chen","userId":"17748361917871513601"}},"outputId":"00fed9ca-3c61-4810-d3c1-8e6eb08ef8e0"},"execution_count":30,"outputs":[{"output_type":"stream","name":"stdout","text":["13\n"]},{"output_type":"execute_result","data":{"text/plain":[]},"metadata":{},"execution_count":30}]},{"cell_type":"markdown","source":["\n","Modules\n","\n","https://en.cppreference.com/w/cpp/language/modules\n","\n","```c++\n","// helloworld.cppm\n","export module helloworld;  \n","import <iostream>;         \n"," \n","export void hello() {      \n","    std::cout << \"Hello world!\\n\";\n","}\n","```\n","\n","```c++\n","// main.cpp\n","import helloworld;  \n"," \n","int main() {\n","    hello();\n","}\n","```\n","\n","\n","\n","Coroutines\n","\n","https://en.cppreference.com/w/cpp/language/coroutines\n"],"metadata":{"id":"snj4eUvl-Lnd"}}],"metadata":{"colab":{"provenance":[{"file_id":"1AB3RNlLfkZBSZKu6_Wh20CkIpbxfJIve","timestamp":1663461789208}],"authorship_tag":"ABX9TyMtPgnOBX2uBOLCGFhlFkig"},"gpuClass":"premium","kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}