Скачать презентацию 17 Part I The Core Language Скачать презентацию 17 Part I The Core Language

Peter-Van-Weert-BeC17-Part-I.pptx

  • Количество слайдов: 111

17 Part I – The Core Language 17 Part I – The Core Language

“I'm a bit sad about that. [. . . ] A lot of minor “I'm a bit sad about that. [. . . ] A lot of minor improvements can add up to something significant. Most of these will help somebody in some way. There's something for everybody here. I can't imagine any C++ programmer that will not have at least some relieve from pain in C++17. That will not be able to write some piece of their code better in C++17. ” – Bjarne Stroustrup , Cpp. Con 2016 keynote

Shameless Self-Promotion Ahead Shameless Self-Promotion Ahead

Shameless Self-Promotion • Co-author: Marc Gregoire • Concise reference (212 pages) • Complete C++14 Shameless Self-Promotion • Co-author: Marc Gregoire • Concise reference (212 pages) • Complete C++14 Standard Library “Very useful quick reference for C++ programmers on some part of the library they have forgotten or in need of a quick refresh. ” “Even the most experienced C++ programmer will learn a thing or two from the book and find it an indispensable reference and memory aid. ”

Overview “A lot of minor improvements can add up to something significant. ” • Overview “A lot of minor improvements can add up to something significant. ” • Part I – The C++ Core Language ▫ Today: more detail ▫ Next year: quick overview • Part II – The C++ Standard Library ▫ Today: quick overview ▫ Next year: more detail

- PART I – THE C++ CORE LANGUAGE - PART I – THE C++ CORE LANGUAGE

Nested Namespaces Nested Namespaces

Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point { double x, y, z; }; typedef std: : vector Cloud; } } }

Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point { double x, y, z; }; typedef std: : vector Cloud; }}}

Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point Nested Namespaces namespace Nikon { namespace Metrology { namespace Point. Clouds { struct Point { double x, y, z; }; typedef std: : vector Cloud; }}}

Nested Namespaces in C++17 namespace Nikon: : Metrology: : Point. Clouds { struct Point Nested Namespaces in C++17 namespace Nikon: : Metrology: : Point. Clouds { struct Point { double x, y, z; }; typedef std: : vector Cloud; }

static_assert(expression) static_assert(expression)

static_assert recap (C++11) struct Point { double x, y, z; }; typedef std: : static_assert recap (C++11) struct Point { double x, y, z; }; typedef std: : vector Cloud; static_assert(sizeof(Point) == 3 * sizeof(double), "Unexpected Point size"); static_assert(is_trivially_copyable: : value, "Point is not trivially copyable"); • Type traits? • When is_trivially_copyable? (check w. safe to memcpy() etc. ) • is_pod? is_trivial? . . .

static_assert recap (C++11) struct Point { double x, y, z; }; typedef std: : static_assert recap (C++11) struct Point { double x, y, z; }; typedef std: : vector Cloud; static_assert(sizeof(Point) == 3 * sizeof(double), "Unexpected Point size"); static_assert(is_trivially_copyable: : value, "Point is not trivially copyable");

static_assert recap (C++11) struct Point { double x, y, z; virtual double Norm(); }; static_assert recap (C++11) struct Point { double x, y, z; virtual double Norm(); }; typedef std: : vector Cloud; static_assert(sizeof(Point) == 3 * sizeof(double), "Unexpected Point size"); Static assertion failed with “Unexpected Point size” static_assert(is_trivially_copyable: : value, "Cloud is not trivially copyable"); Static assertion failed with “Cloud is not trivially coyable”

static_assert in C++17 struct Point { double x, y, z; virtual double Norm(); }; static_assert in C++17 struct Point { double x, y, z; virtual double Norm(); }; typedef std: : vector Cloud; static_assert(sizeof(Point) == 3 * sizeof(double)); Static assertion failed: sizeof(Point) == 3 * sizeof(double) static_assert(is_trivially_copyable: : value); Static assertion failed: is_trivially_copyable: : value

Structured Bindings Structured Bindings

std: : tuple quick recap (C++11) std: : tuple<int, std: : string, int> triple(); std: : tuple quick recap (C++11) std: : tuple triple(); auto t = tripple(); auto& x = std: : get<0>(t); auto& y = std: : get(t); auto& z = std: : get<2>(t); // C++14

std: : tuple quick recap (C++11) std: : tuple<int, std: : string, int> triple(); std: : tuple quick recap (C++11) std: : tuple triple(); int x, z; string y; std: : tie(x, y, z) = tripple(); • std: tuple? • std: : tie()? • Tip: tie() for operator

std: : tuple quick recap (C++11) std: : tuple<int, std: : string, int> triple(); std: : tuple quick recap (C++11) std: : tuple triple(); int x, z; string y; std: : tie(x, y, z) = tripple(); // Declare // Tie

Structured Bindings (C++17) std: : tuple<int, std: : string, int> tripple(); auto [x, y, Structured Bindings (C++17) std: : tuple tripple(); auto [x, y, z] = tripple(); // Declare and tie!

Structured Bindings /* Case 1: C-style arrays --> expr[i] */ int array[3] { 1, Structured Bindings /* Case 1: C-style arrays --> expr[i] */ int array[3] { 1, 2, 3 }; auto [one, two, three] = array; /* Case 2: valid std: : tuple_size: : value --> expr. get() or get(expr) (ADL) */ std: : tuple t; auto [x, y, z] = t; // Also: std: : array<> std: : array abc{ 'a', 'b', 'c' }; auto [a, b, c] = abc;

Structured Bindings /* Case 3: all non-static members are public */ // Typical for Structured Bindings /* Case 3: all non-static members are public */ // Typical for C-style structs struct Point { double m_x, m_y, m_z; }; Point point { 0, 0, 0 }; auto [x, y, z] = point; // Also: std: : pair<>! std: : map map; auto [iter, success] = map. insert("Answer", 42); for (const auto& [key, value] : map) { /*. . . */ }

Structured Bindings /* Case 3: all non-static members are public */ // Typical for Structured Bindings /* Case 3: all non-static members are public */ // Typical for C-style structs struct Point { double m_x, m_y, m_z; }; Point point { 0, 0, 0 }; auto [x, y, z] = point; // Also: std: : pair<>! std: : map map; auto [iter, success] = map. insert("Answer", 42); for (const auto& [key, value] : map) { /*. . . */ }

Structured Bindings Q&A Move or copy? Move! ‘auto [a, b] = {1, Structured Bindings Q&A Move or copy? Move! ‘auto [a, b] = {1, "two"}’? Not yet. . . ‘[x, y, z] = tripple()’? Not yet: use tie(). . . ‘auto [&a, const b] =. . . ’? No. ‘string [a, b] =. . . ’? No. ‘auto [a, string b] =. . . ’? No. ‘auto [x, std: : ignore, z] =. . . ’? Not yet: anticipate pattern matching (like _ or *) • ‘auto [x, [a, b], z] =. . . ’? Not yet. . . • •

Custom Structured Bindings /* Case 1: C-style arrays --> expr[i] Case 2: valid std: Custom Structured Bindings /* Case 1: C-style arrays --> expr[i] Case 2: valid std: : tuple_size: : value --> expr. get() or get(expr) (ADL) Case 3: all non-static members are public */ namespace Nikon { class Point { private: double m_x, m_y, m_z; public: double X() const; double Y() const; double Z() const; }; }

Custom Structured Bindings /* Case 2: valid std: : tuple_size<decltype(expr)>: : value --> expr. Custom Structured Bindings /* Case 2: valid std: : tuple_size: : value --> expr. get() or get(expr) (ADL) */ namespace std { template<> struct tuple_size : public integral_constant {}; }

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace std { template<> struct tuple_size : public integral_constant template<> struct tuple_element<0, Nikon: : Point> { using type template<> struct tuple_element<1, Nikon: : Point> { using type template<> struct tuple_element<2, Nikon: : Point> { using type } {}; = double; };

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace Nikon { class Point; template auto get(const Point&) = delete; template<> auto get<0>(const Point& p) { return p. X(); }; template<> auto get<1>(const Point& p) { return p. Y(); }; template<> auto get<2>(const Point& p) { return p. Z(); }; }

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace Nikon { class Point; template auto get(const Point&) = delete; template<> auto get<0>(const Point& p) { return p. X(); }; template<> auto get<1>(const Point& p) { return p. Y(); }; template<> auto get<2>(const Point& p) { return p. Z(); }; }

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace Nikon { class Point { /*. . . */ template auto get() const = delete; template<> auto get<0>() const { return p. X(); }; template<> auto get<1>() const { return p. Y(); }; template<> auto get<2>() const { return p. Z(); }; }; } Explicit specialization in non-namespace scope 'class Point'

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace Nikon { class Point { /*. . . */ template auto get() = { return get(std: : integral_constant) { auto get(std: : integral_constant) { auto get(std: : integral_constant) { }; } I>()); }; return m_x; } return m_y; } return m_z; }

Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size<T>: Custom Structured Bindings /* Case 2: let T = decltype(expr), and std: : tuple_size: : value is valid --> std: : tuple_element: : type = expr. get() or std: : tuple_element: : type = get(expr) (ADL) */ namespace std { /*. . . */ } namespace Nikon { class Point { /*. . . */ }; } Nikon: : Point p; /*. . . */ auto [x, y, z] = p;

Initializers for if & switch Initializers for if & switch

Declare-and-null-check Idiom Widget* Gimme. Widget(); if (auto widget = Gimme. Widget()) { // widget Declare-and-null-check Idiom Widget* Gimme. Widget(); if (auto widget = Gimme. Widget()) { // widget can be used in this scope. . . } // widget cannot be user here. . .

Assign-and-null-check Idiom Widget* Gimme. Widget(); { Widget* widget; //. . . if (widget = Assign-and-null-check Idiom Widget* Gimme. Widget(); { Widget* widget; //. . . if (widget = Gimme. Widget()) { //. . . Did you mean “widget == Gimme. Widget()”? } } // widget cannot be used here. . .

Assign-and-null-check Idiom Widget* Gimme. Widget(); { Widget* widget; //. . . if ((widget = Assign-and-null-check Idiom Widget* Gimme. Widget(); { Widget* widget; //. . . if ((widget = Gimme. Widget())) { //. . . } } // widget cannot be used here. . .

Checks Different from Null-checks? (Before) { auto result = map. insert(key, val); if (result. Checks Different from Null-checks? (Before) { auto result = map. insert(key, val); if (result. second) { process(*result. first); } else { FATAL("Duplicate"); } } // result cannot be used here. . .

Other Checks: Initializers (C++17) if (auto result = map. insert(key, val); result. second) { Other Checks: Initializers (C++17) if (auto result = map. insert(key, val); result. second) { process(*result. first); } else { FATAL("Duplicate"); } // result cannot be used here. . .

Or of course. . . (C++17) if (auto [iter, success] = map. insert(key, val); Or of course. . . (C++17) if (auto [iter, success] = map. insert(key, val); success){ process(*iter); } else { FATAL("Duplicate"); } // iter or success cannot be used here. . .

Initializers: Other Use Cases /* Locks */ if (std: : lock_guard<std: : mutex> lock; Initializers: Other Use Cases /* Locks */ if (std: : lock_guard lock; shared_vec. empty()) { shared_vec. push_back(42); } /* Local variable(s) for output parameter(s) */ if (Widget w; Get. Widgets(&w)) { process(w); } if (Widget w 1, w 2; Get. Widgets(&w 1, &w 2)){ process(w 1); process(w 2); }

Initializers for Switches switch (auto widget = Gimme. Widget(); widget->Get. Phalangy()) { case 123: Initializers for Switches switch (auto widget = Gimme. Widget(); widget->Get. Phalangy()) { case 123: /* widget can be used here as well. . . */ } switch (std: : lock_guard lock; shared_val) { case 123: /*. . . */ }

constexpr if constexpr if

constexpr if • Written ‘if constexpr(expression)’ • Statically evaluated during template instantiation ▫ In constexpr if • Written ‘if constexpr(expression)’ • Statically evaluated during template instantiation ▫ In other words: expression must be a constexpr • One of the branches is discarded ▫ Does not discard static_assert()s • Easier and more readable than multiple overloads or template specializations, SFINAE, . . .

Example 1: recursive pack unpacking template <typename Single> void Print(Single&& value) { std: : Example 1: recursive pack unpacking template void Print(Single&& value) { std: : cout << value << std: : endl; } template void Print(Head&& head, Tail&&. . . tail) { Print(head); Print(tail. . . ); } Print(123, "123", 1. 23);

Example 1: recursive pack unpacking template <typename Head, typename. . . Tail> Print(Head&& head, Example 1: recursive pack unpacking template Print(Head&& head, Tail&&. . . tail) { std: : cout << head << std: : endl; if constexpr(sizeof. . . (tail)) { Print(std: : forward(tail). . . ); } } Print(123, "123", 1. 23);

Example 2: std: : enable_if / SFINAE template <typename T> std: : enable_if_t<std: : Example 2: std: : enable_if / SFINAE template std: : enable_if_t: : value> Handle(T&& value) { Handle. Integral. Value(std: : forward(value)); } template std: : enable_if_t: : value> Handle(T&& value) { • Type traits? Handle. Any. Other. Value(std: : forward(value)); • std: : enable_if(_t)? } • SFINAE?

Example 2: std: : enable_if / SFINAE template <typename T> void Handle(T&& value) { Example 2: std: : enable_if / SFINAE template void Handle(T&& value) { if constexpr(std: : is_integral: : value) Handle. Integral. Value(std: : forward(value)); else Handle. Any. Other. Value(std: : forward(value)); }

Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ namespace Nikon { class Point { /*. . . */ template auto get() = { return get(std: : integral_constant) { auto get(std: : integral_constant) { auto get(std: : integral_constant) { }; } I>()); }; return m_x; } return m_y; } return m_z; }

Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ namespace Nikon { class Point { /*. . . */ template auto get() { if constexpr(I == 0) { return m_x; } if constexpr(I == 1) { return m_y; } if constexpr(I == 2) { return m_z; } } }; }

Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ namespace Nikon { class Point { /*. . . */ template auto get() { if constexpr(I == 0) { return m_x; } else if constexpr(I == 1) { return m_y; } else if constexpr(I == 2) { return m_z; } else static_assert(false); } }; }

Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ Example 3: Specializations of (Member) Template Functions /* Custom structured bindings. . . */ namespace Nikon { class Point { /*. . . */ template auto get() { static_assert(I < 3); if constexpr(I == 0) { return m_x; } if constexpr(I == 1) { return m_y; } if constexpr(I == 2) { return m_z; } }; }

Fold Expressions Fold Expressions

Folds over Parameter Packs auto sum() { return 0; } template <typename Head, typename. Folds over Parameter Packs auto sum() { return 0; } template auto sum(const Head& head, const Tail&. . . tail) { return head + sum(tail. . . ); } std: : cout << sum(1, 2. 0, 3) << std: : endl; // 6. 0

Fold Expression template <typename. . . T> void sum(const T&. . . values) { Fold Expression template void sum(const T&. . . values) { return (values +. . . ); }

Fold Expressions (pack . . . ) pack 0 (. . . (packn-1 packn)) Fold Expressions (pack . . . ) pack 0 (. . . (packn-1 packn)) (. . . pack) ((pack 0 pack 1) . . . ) packn (pack . . . val) pack 0 (. . . (packn-1 (packn val))) (val . . . pack) (((val pack 0) pack 1) . . . ) packn With one of + - * /  % ^ &  | << >> += -= *= /= %= ^= &= |= <<= >>= = == != < > <= >= && || , . * ->*

Fold Expressions (pack . . . ) pack 0 (. . . (packn-1 packn)) Fold Expressions (pack . . . ) pack 0 (. . . (packn-1 packn)) (. . . pack) ((pack 0 pack 1) . . . ) packn (pack . . . val) pack 0 (. . . (packn-1 (packn val))) (val . . . pack) (((val pack 0) pack 1) . . . ) packn With one of + - * /  % ^ &  | << >> += -= *= /= %= ^= &= |= <<= >>= = == != < > <= >= && || , . * ->*

Fold Expressions: operator , template <typename Single> void Print(const Single& value) { std: : Fold Expressions: operator , template void Print(const Single& value) { std: : cout << value << " "; } template void Print(const Head& head, const Tail&. . . tail) { Print(head); Print(tail. . . ); } Print(123, "123", 1. 23); // 123 1. 23

Right Fold with operator , template <typename Single> void Print(const Single& value) { std: Right Fold with operator , template void Print(const Single& value) { std: : cout << value << " "; } template void Print(const Pack&. . . pack) { (Print(pack), . . . ); } Print(123, "123", 1. 23); // 123 1. 23

Left Fold with operator << template <typename. . . Pack> void Print(const Pack&. . Left Fold with operator << template void Print(const Pack&. . . pack) { (std: : cout <<. . . << pack); } Print(123, "123", 1. 23); // 1231231. 23

Template Argument Deduction for Constructors Template Argument Deduction for Constructors

Examples (Before) std: : pair<int, double> p(2, 4. 5); auto t = std: : Examples (Before) std: : pair p(2, 4. 5); auto t = std: : make_tuple(4, 3, 2. 5); std: : copy(a, a+3, std: : back_inserter(v)); // Virtually impossible to pass a lambda to a template // class' constructor without declaring the lambda for_each(begin(v), end(v), Foo([&](int i) { })); std: : lock_guard lck(foo. m_mutex); std: : lock_guard> lck 2(foo. m_mutex, ul);

Examples (C++17) std: : pair p(2, 4. 5); std: : tuple t(4, 3, 2. Examples (C++17) std: : pair p(2, 4. 5); std: : tuple t(4, 3, 2. 5); std: : copy(a, a+3, std: : back_insert_iterator(v)); // Now easy instead of virtually impossible to pass a // lambda to a template class' constructor. . . for_each(begin(v), end(v), Foo([&](int i) { })); auto lck = std: : lock_guard(foo. m_mutex); std: : lock_guard lck 2(foo. m_mutex, ul); // New in C++17

Explicit Deduction Guides namespace std { template<typename T> class vector { /*. . . Explicit Deduction Guides namespace std { template class vector { /*. . . */ }; } auto v = std: : vector(3, 'x'); // std: : vector? ? ?

Explicit Deduction Guides namespace std { template<typename T> class vector { /*. . . Explicit Deduction Guides namespace std { template class vector { /*. . . */ }; template vector(int, T) -> vector; } auto v = std: : vector(3, 'x'); // std: : vector!

Capture *this Capture *this

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args) { std: : thread(std: : forward(f), std: : forward(args). . . ). detach(); } • Why detach()? • Why not std: : async()? • What is perfect forwarding?

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { int m_bar; public: void lish() { int bar = 123; Fire. And. Forget([=] { cout << bar << endl; }); } };

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { { int m_bar; Foo foo; public: foo. lish(); void lish() { } int bar = 123; Fire. And. Forget([=] { cout << bar + m_bar << endl; }); } };

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { int m_bar; public: void lish() { int bar = 123; Fire. And. Forget([=, m_bar=m_bar] // C++14 { cout << bar + m_bar << endl; }); } };

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { int m_bar; public: void lish() { int bar = 123; Fire. And. Forget([=, copy=m_bar] // C++14 { cout << bar + copy << endl; }); } };

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { int m_bar; public: void lish() { int bar = 123; Fire. And. Forget([=, copy=*this] // C++14 { cout << bar + copy. m_bar << endl; }); } };

Lambdas: Capture *this // Asynchronously execute f(args) template <typename Function, typename. . . Args> Lambdas: Capture *this // Asynchronously execute f(args) template void Fire. And. Forget(Function&& f, Args&&. . . args); class Foo { int m_bar; public: void lish() { int bar = 123; Fire. And. Forget([=, *this] // C++17 { cout << bar + m_bar << endl; }); } };

Lambdas: Capture *this class Foo { int m_bar; public: void lish(); // foofaraw (fo Lambdas: Capture *this class Foo { int m_bar; public: void lish(); // foofaraw (fo o′fə-rô): a fuss over something trivial std: : function faraw() { return [*this](int i) { return m_bar + i; }; } };

Attributes • Attributes for namespaces and enumerators • [[fallthrough]], [[nodiscard]], [[maybe_unused]] • using for Attributes • Attributes for namespaces and enumerators • [[fallthrough]], [[nodiscard]], [[maybe_unused]] • using for attributes (namespaces)

Attributes recap (C++11 / C++14) • [[noreturn]] void Raise. Hell(); void Raise. Hell() { Attributes recap (C++11 / C++14) • [[noreturn]] void Raise. Hell(); void Raise. Hell() { throw Hell(); }; • [[deprecated]] class [[deprecated]] Foo {}; struct Bar { [[deprecated]] int m_abas; } [[deprecated("Use Raise. Hell() instead")]] void Raise. Inferno(); • [[carries_dependency]]

Attributes for namespaces and enumerators (C++17) namespace [[deprecated]] Legacy. Stuff { /*. . . Attributes for namespaces and enumerators (C++17) namespace [[deprecated]] Legacy. Stuff { /*. . . */ }; namespace [[deprecated]] { /*. . . */ }; enum [[deprecated]] Legacy. Enum; // Possible since C++14 enum Error. Code { catastrofic, faulty, flawed [[deprecated("Use 'faulty' instead")]], iffy, okayish, peachy, hunkydory [[deprecated("Use 'peachy' instead")]] }

[[fallthrough]] switch (number) { case 111: case 222: Do. Something(); break; case 333: Do. [[fallthrough]] switch (number) { case 111: case 222: Do. Something(); break; case 333: Do. Something. Else(); case 444: Do. Some. More(); break; // Continued to the right… default: assert(false); case 555: if (Should. I()) Do. Something(); else { Do. Something. Else(); break; } case 666: Raise. Hell(); case 777: Do. Something. Different(); }

[[fallthrough]] default: assert(false); [[fallthrough]]; case 555: if (Should. I()) { Do. Something(); [[fallthrough]]; } [[fallthrough]] default: assert(false); [[fallthrough]]; case 555: if (Should. I()) { Do. Something(); [[fallthrough]]; } else { Do. Something. Else(); break; } case 666: Raise. Hell(); case 777: Do. Something. Different(); switch (number) { case 111: case 222: Do. Something(); break; case 333: Do. Something. Else(); [[fallthrough]]; case 444: Do. Some. More(); break; // Continued to the right… }

[[nodiscard]] • Why does std: : async() become synchronous? typedef int write the /*. [[nodiscard]] • Why does std: : async() become synchronous? typedef int write the /*. . . */ using type traits? • How to errorcode; errorcodedeclare using && (perfect forwarding)? • Why Do. Something(); errorcode Do. Something. Else(); template std: : future async(Function&&, Args&&. . . ); void main() { async( [] { Do. Something(); } ); Do. Something. Else(); std: : cout << "Did it!" << std: : endl; }

[[nodiscard]] typedef int errorcode; [[nodiscard]] errorcode Do. Something(); [[nodiscard]] errorcode Do. Something. Else(); template [[nodiscard]] typedef int errorcode; [[nodiscard]] errorcode Do. Something(); [[nodiscard]] errorcode Do. Something. Else(); template [[nodiscard]] std: : future async(F&&, Args&&. . . ); void main() { async( [] { Do. Something(); } ); Do. Something. Else(); std: : cout << "Did it!" << std: : endl; }

[[nodiscard]] enum errorcode; [[nodiscard]] errorcode Do. Something(); [[nodiscard]] errorcode Do. Something. Else(); template <typename [[nodiscard]] enum errorcode; [[nodiscard]] errorcode Do. Something(); [[nodiscard]] errorcode Do. Something. Else(); template [[nodiscard]] std: : future async(F&&, Args&&. . . ); void main() { async( [] { Do. Something(); } ); Do. Something. Else(); std: : cout << "Did it!" << std: : endl; }

[[nodiscard]] // [[nodiscard]] on class, enum, or function declaration enum [[nodiscard]] errorcode; errorcode Do. [[nodiscard]] // [[nodiscard]] on class, enum, or function declaration enum [[nodiscard]] errorcode; errorcode Do. Something(); errorcode Do. Something. Else(); template [[nodiscard]] std: : future async(F&&, Args&&. . . ); void main() { async( [] { Do. Something(); } ); Do. Something. Else(); std: : cout << "Did it!" << std: : endl; }

[[nodiscard]] enum [[nodiscard]] errorcode; errorcode Do. Something(); errorcode Do. Something. Else(); template <typename F, [[nodiscard]] enum [[nodiscard]] errorcode; errorcode Do. Something(); errorcode Do. Something. Else(); template [[nodiscard]] std: : future async(F&&, Args&&. . . ); void main() { auto future. Error = async([] { return Do. Something(); }); auto error = Do. Something. Else(); if (Is. Success(error) && Is. Success(future. Error. get())) std: : cout << "Did it!" << std: : endl; }

[[maybe_unused]] [[nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log(errorcode ec) { #ifdef _LOGGING [[maybe_unused]] [[nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log(errorcode ec) { #ifdef _LOGGING if (!Test. Success(ec)) std: : err << "Epic Fail!n"; #endif } void main() { auto result = Do. Something(); assert(Test. Success(result)); }

[[maybe_unused]] [[nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log(errorcode ec) { #ifdef _LOGGING [[maybe_unused]] [[nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log(errorcode ec) { #ifdef _LOGGING if (!Test. Success(ec)) std: : err << "Epic Fail!n"; #endif } void main() { auto result = Do. Something(); assert(Test. Success(result)); }

[[maybe_unused]] [[maybe_unused, nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log([[maybe_unused]] errorcode ec) { [[maybe_unused]] [[maybe_unused, nodiscard]] bool Test. Success(errorcode); errorcode Do. Something(); void log([[maybe_unused]] errorcode ec) { #ifdef _LOGGING if (!Test. Success(ec)) std: : err << "Epic Fail!n"; #endif } void main() { [[maybe_unused]] auto result = Do. Something(); assert(Test. Success(result)); }

using for Attributes void f() { [[rpr: : pipeline(bound, 8, blocking), rpr: : stream(A, using for Attributes void f() { [[rpr: : pipeline(bound, 8, blocking), rpr: : stream(A, B)]] for (int i = 0; i < iterations ; ++i) { [[rpr: : kernel, rpr: : out(a), rpr: : target(cpu)]] a = get_value(); [[rpr: : kernel, rpr: : farm(4, ordered), rpr: : in(A, C), rpr: : out(A, B), rpr: : target(cpu, gpu)]] for (int j = 0; j < max; ++j) b = f(a, c ); [[rpr: : kernel, rpr: : in(A, B)]] g(a, b); }}

using for Attributes void f() { [[using rpr: pipeline(bound, 8, blocking), stream(A, B)]] for using for Attributes void f() { [[using rpr: pipeline(bound, 8, blocking), stream(A, B)]] for (int i = 0; i < iterations ; ++i) { [[using rpr: kernel, out(a), target(cpu)]] a = get_value(); [[using rpr: kernel, farm(4, ordered), in(A, C), out(A, B), target(cpu, gpu)]] for (int j = 0; j < max; ++j) b = f(a, c ); [[using rpr: kernel, in(A, B)]] g(a, b); }}

using for Attributes void f() { [[using rpr: pipeline(bound, 8, blocking), stream(A, B)]] for using for Attributes void f() { [[using rpr: pipeline(bound, 8, blocking), stream(A, B)]] for (int i = 0; i < iterations ; ++i) { [[using rpr: kernel, out(a), target(cpu)]] [[deprecated]] a = get_value(); [[using rpr: kernel, farm(4, ordered), in(A, C), out(A, B), target(cpu, gpu)]] for (int j = 0; j < max; ++j) b = f(a, c ); [[using rpr: kernel, in(A, B)]] g(a, b); }}

Changes to Semantics Changes to Semantics

Guaranteed Copy Elision • When a temporary object is used to initialize another object Guaranteed Copy Elision • When a temporary object is used to initialize another object • Including the object returned by a function, or the exception object created by a throw-expression T f() { return T{}; // no copy here (C++17) } T x = f(); T g() { T t; return t; } // no copy here either (C++17) // copy may be elided but not guaranteed

auto x{expr} int a = 1; int b(2); int c{3}; (C++11 / C++14) auto auto x{expr} int a = 1; int b(2); int c{3}; (C++11 / C++14) auto d = 1; auto e(2); auto f{3}; #define ASSERT_TYPE(EXPR, T) static_assert(std: : is_same: : value) ASSERT_TYPE(a, int); ASSERT_TYPE(b, int); ASSERT_TYPE(c, int); ASSERT_TYPE(d, int); ASSERT_TYPE(e, int); // But! ASSERT_TYPE(f, std: : initializer_list);

auto x{expr} int a = 1; int b(2); int c{3}; (C++17) auto d = auto x{expr} int a = 1; int b(2); int c{3}; (C++17) auto d = 1; auto e(2); auto f{3}; #define ASSERT_TYPE(EXPR, T) static_assert(std: : is_same: : value) ASSERT_TYPE(a, int); ASSERT_TYPE(b, int); ASSERT_TYPE(c, int); ASSERT_TYPE(d, int); ASSERT_TYPE(e, int); ASSERT_TYPE(f, int);

f( auto_ptr<T 1>( new T 1 ), auto_ptr<T 2>( new T 2 ) ); f( auto_ptr( new T 1 ), auto_ptr( new T 2 ) ); Undefined Evaluation Order (before) std: : map m; m[0] = m. size(); // m[0] == 0 or m[0] == 1 int i = 3; m[i] = ++i; // m[3] == 4 or m[4] == 4 // Got. W 56 -- potential leak: use make_unique (C++14)! f(unique_ptr(new Foo), unique_ptr(new Bar)); // The C++ Programming Language, 4 th Edition (assertion possible) std: : string s = "but I have heard it works even if you don't believe in it"; s. replace(0, 4, ""). replace(s. find("even"), 4, "only"). replace(s. find(" don't"), 6, ""); assert(s == "I have heard it works only if you believe in it");

Refined Expression Evaluation Order (C++17) 1. 2. 3. 4. 5. 6. 7. 8. 9. Refined Expression Evaluation Order (C++17) 1. 2. 3. 4. 5. 6. 7. 8. 9. a. b a->*b a(bi, bj, bk) b=a b @= a a[b] a << b a >> b

f( auto_ptr<T 1>( new T 1 ), auto_ptr<T 2>( new T 2 ) ); f( auto_ptr( new T 1 ), auto_ptr( new T 2 ) ); Undefined Evaluation Order (C++17) std: : map m; m[0] = m. size(); // m[0] == 0 int i = 3; m[i] = ++i; // m[4] == 4 // Got. W 56 -- no leak! f(unique_ptr(new Foo), unique_ptr(new Bar)); // The C++ Programming Language, 4 th Edition (never asserts) std: : string s = "but I have heard it works even if you don't believe in it"; s. replace(0, 4, ""). replace(s. find("even"), 4, "only"). replace(s. find(" don't"), 6, ""); assert(s == "I have heard it works only if you believe in it");

C++17 Language Changes C++17 Language Changes

Seen Today • • • Nested namespaces static_assert(expr) for-like initializers for if and switch Seen Today • • • Nested namespaces static_assert(expr) for-like initializers for if and switch Structured bindings Constexpr if Fold expressions Capture *this Attributes Changes to semantics

Also Added in C++17. . . • Hexadecimal floating literals: 0 x 3. ABCp-10 Also Added in C++17. . . • Hexadecimal floating literals: 0 x 3. ABCp-10 • UTF-8 character literals: u 8'U', u 8'T', u 8'F', u 8'8' • Preprocessor test for existence of headers: #if __has_include() • Type deduction for non-type template parameters E. g. template struct S; • constexpr lambdas • Dynamic memory allocation for over-aligned data • Inline variables (cf. inline funtions) • . . .

Features Removed from C++17 • register keyword ▫ Reserved for future use • ++ Features Removed from C++17 • register keyword ▫ Reserved for future use • ++ operator for bool • Trigraphs ▫ ? ? = # ? ? / ? ? ’ ^ ? ? ( [ ? ? ! |. . .

- PART II - THE C++ STANDARD LIBRARY - PART II - THE C++ STANDARD LIBRARY

“Vocabulary Types” • std: : optional<T> ▫ Optional values • std: : variant<Ts. . “Vocabulary Types” • std: : optional ▫ Optional values • std: : variant ▫ Type safe unions • std: : any ▫ Type safe void* • std: : string_view ▫ Efficient OO algorithms (no copying!) that work on const std: : string&, C-style strings, literals, . . .

Containers • try_emplace() and insert_or_assign() • Splicing for associative containers ▫ Move nodes between Containers • try_emplace() and insert_or_assign() • Splicing for associative containers ▫ Move nodes between containers ▫ Merge whole containers • Non-const data() for strings • Non-member std: : size(), std: : empty(), std: : data() ▫ Cf. std: : begin()/end() • . . .

Algorithms • std: : search() ▫ Boyer-Moore and Boyer-Moore-Horspool substring search algorithms • std: Algorithms • std: : search() ▫ Boyer-Moore and Boyer-Moore-Horspool substring search algorithms • std: : sample() ▫ Random sampling from a range • std: : clamp() ▫ Clamping between min and max value • Parallelism TS 1 ▫ 69 parallel versions of existing algorithms ▫ New parallel reduce-like algorithm

Threading • std: : shared_mutex ▫ Multiple readers-single writer lock • std: : lock_guard<Mutexes. Threading • std: : shared_mutex ▫ Multiple readers-single writer lock • std: : lock_guard ▫ Alternative to std: : lock() • std: : hardware_*_interference_size ▫ Query cache-line size • . . .

File System TS • Standard file system API for C++ ▫ ▫ ▫ ▫ File System TS • Standard file system API for C++ ▫ ▫ ▫ ▫ Absolute paths Relative paths Files and directories Links Creating Copying Renaming. . .

More C++17 Standard Library. . . • Smart pointer improvements • Memory management tools More C++17 Standard Library. . . • Smart pointer improvements • Memory management tools • Special math functions ▫ Bessel, Neumann, Legendre, hypergeometric, . . . • Type traits ▫ trait_v shorthand for trait: : value ▫ std: : void_t ▫ std: : conjunction, disjunction, and negation • Efficient, locale-independent parsing and formatting of integers and floating point numbers • . . .

Find out more? • C++ Standards Committee Papers ▫ http: //www. open-std. org/jtc 1/sc Find out more? • C++ Standards Committee Papers ▫ http: //www. open-std. org/jtc 1/sc 22/wg 21/docs/papers/ ▫ ‘Adopted’ papers • Stack. Overflow ‘What are the new features in C++17? ’ ▫ http: //stackoverflow. com/questions/38060436/whatare-the-new-features-in-c 17/38060437#38060437 ▫ Warning: many outdated links • Sutter's Mill ▫ https: //herbsutter. com ▫ ‘Trip reports’ posts • Notes of this presentation. . .