c++20: the small thingsc++20: pack expansion allowed in lambda init capture. 52 – lambdas are...

114
Timur Doumler MeetingC++ 14 November 2019 C++20: The small things @timur_audio Version 1.3

Upload: others

Post on 31-Mar-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Timur Doumler

MeetingC++ 14 November 2019

C++20: The small things

@timur_audio

Version 1.3

Page 2: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 3: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 4: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 5: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

we are here

Page 6: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 7: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 8: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 9: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 10: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible
Page 11: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

11

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 12: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

12

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 13: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Aggregates

13

struct Widget { int a; bool b; int c; };

Page 14: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Aggregates

14

struct Widget { int a; bool b; int c; };

int main() { Widget widget = {3, true}; }

Page 15: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Designated initialisers

15

struct Widget { int a; bool b; int c; };

int main() { Widget widget{.a = 3, .c = 7}; }

Page 16: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

16

struct Widget { int a; bool b; int c; };

int main() { Widget widget{.a = 3, .c = 7}; }

Only for aggregate types.

C compatibility feature.

Works like in C99, except: • not out-of-order

Widget widget{.c = 7, .a = 3} // Error • not nested

Widget widget{.c.e = 7} // Error • not mixed with regular initialisers

Widget widget{.a = 3, 7} // Error • not with arrays

int arr[3]{.[1] = 7} // Error

Designated initialisers

Page 17: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

17

Page 18: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

18

Aggregates can no longer declare constructors

Page 19: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

19

struct Widget { Widget() = delete; };

Widget w1; // Error

Aggregates can no longer declare constructors

Page 20: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

20

struct Widget { Widget() = delete; };

Widget w1; // Error Widget w2{}; // OK in C++17!

Aggregates can no longer declare constructors

Page 21: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

21

struct Widget { Widget() = delete; };

Widget w1; // Error Widget w2{}; // OK in C++17! Will be error in C++20

Aggregates can no longer declare constructors

Page 22: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

• Does not work with macros:

22

assert(Widget(2, 3)); // OK

C++17 problems with aggregate initialisation:

Page 23: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

• Does not work with macros:

23

assert(Widget(2, 3)); // OK assert(Widget{2, 3}); // Error: this breaks the preprocessor :(

C++17 problems with aggregate initialisation:

Page 24: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

• Does not work with macros:

• Can’t do perfect forwarding in templates • can’t write emplace or make_unique that works for aggregates :(

24

assert(Widget(2, 3)); // OK assert(Widget{2, 3}); // Error: this breaks the preprocessor :(

C++17 problems with aggregate initialisation:

Page 25: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

25

struct Widget { int i; int j; };

Widget widget(1, 2); // will work in C++20!

C++20: Direct-initialisation of aggregates

Page 26: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

26

struct Widget { int i; int j; };

Widget widget(1, 2); // will work in C++20! int arr[3](0, 1, 2); // will work in C++20!

C++20: Direct-initialisation of aggregates

Page 27: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

27

struct Widget { int i; int j; };

Widget widget(1, 2); // will work in C++20! int arr[3](0, 1, 2); // will work in C++20!

So in C++20, (args) and {args} will do the same thing!

Except: • () does not call std::initializer_list constructors

• {} does not allow narrowing conversions

C++20: Direct-initialisation of aggregates

Page 28: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

28

struct Colour { Colour(int r, int g, int b) noexcept; };

constinit

Page 29: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

29

struct Colour { Colour(int r, int g, int b) noexcept; };

namespace Colours { const Colour red = {255, 0, 0}; }

constinit

Page 30: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

30

struct Colour { Colour(int r, int g, int b) noexcept; };

namespace Colours { const Colour red = {255, 0, 0}; // dynamic initialisation }

constinit

Page 31: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

31

struct Colour { Colour(int r, int g, int b) noexcept; };

namespace Colours { const Colour red = {255, 0, 0}; // dynamic initialisation } // -> initialisation order fiasco -> UB :(

constinit

Page 32: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

32

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { constexpr Colour red = {255, 0, 0}; }

constinit

Page 33: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

33

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { constexpr Colour red = {255, 0, 0}; // constant initialisation :) }

constinit

Page 34: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { Colour backgroundColour = getBackgroundColour(); }

34

constinit

Page 35: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { Colour backgroundColour = getBackgroundColour(); // const or dynamic init? }

35

constinit

Page 36: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { constinit Colour backgroundColour = getBackgroundColour(); }

36

constinit

Page 37: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

37

constinit

struct Colour { constexpr Colour(int r, int g, int b) noexcept; };

namespace Colours { constinit Colour backgroundColour = getBackgroundColour(); } // ^^^^^^ only compiles if init happens at compile time :)

Page 38: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Database getDatabase();

for (auto&& user : getDatabase().getUsers()) { registerUser(user); }

38

Range-based for with initialiser

C++17

Page 39: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Database getDatabase();

for (auto&& user : getDatabase().getUsers()) // maybe undefined behaviour! { registerUser(user); }

39

Range-based for with initialiser

C++17

Page 40: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Database getDatabase();

auto db = getDatabase(); for (auto&& user : db.getUsers()) { registerUser(user); }

40

Range-based for with initialiser

C++17

Page 41: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Database getDatabase();

{ auto db = getDatabase(); for (auto&& user : db.getUsers()) { registerUser(user); } }

41

Range-based for with initialiser

C++17

Page 42: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

42

Range-based for with initialiser

Database getDatabase();

for (auto db = getDatabase(); auto&& user : db.getUsers()) { registerUser(user); }

C++20

Page 43: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

43

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 44: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

44

struct Widget { int i; bool b; };

auto [a, b] = getWidget();

Page 45: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

45

struct Widget { int i; bool b; };

auto [a, b] = getWidget(); static [a, b] = getWidget(); // Error in C++17 thread_local [a, b] = getWidget(); // Error in C++17

Page 46: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

46

struct Widget { int i; bool b; };

auto [a, b] = getWidget(); static [a, b] = getWidget(); // OK in C++20 thread_local [a, b] = getWidget(); // OK in C++20

Page 47: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

47

struct Widget { int i; bool b; };

auto [a, b] = getWidget();

auto f = [a]{ return a > 0; }; // Error in C++17: // capture ‘a’ does not name a variable

Page 48: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

48

struct Widget { int i; bool b; };

auto [a, b] = getWidget();

auto f = [a]{ return a > 0; }; // OK in C++20

Page 49: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

49

struct Widget { int i; bool b; };

auto [a, b] = getWidget();

auto f = [a]{ return a > 0; }; // OK in C++20 // copies ‘a’, not the whole object

Page 50: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

50

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 51: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

template<class F, class... Args> auto delay_invoke(F f, Args... args) { return [f = std::move(f), ...args = std::move(args)]() -> decltype(auto) { return std::invoke(f, args...); }; }

51

C++20: pack expansion allowed in lambda init capture

Page 52: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

52

– Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible and assignable

More C++20 lambda features:

Page 53: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

53

– Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible and assignable

More C++20 lambda features:

decltype([]{})

Page 54: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

54

– Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible and assignable

More C++20 lambda features:

decltype([]{}) f;

Page 55: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

55

– Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible and assignable

More C++20 lambda features:

class Widget { decltype([]{}) f; };

Page 56: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

56

template <typename T> using MyPtr = std::unique_ptr< T, decltype([](T* t) { myDeleter(t); })>;

MyPtr<Widget> ptr;

Page 57: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

57

template <typename T> using MyPtr = std::unique_ptr< T, decltype([](T* t) { myDeleter(t); })>;

MyPtr<Widget> ptr;

using WidgetSet = std::set< Widget, decltype([](Widget& lhs, Widget& rhs) { return lhs.x < rhs.x; })>;

WidgetSet widgets;

Page 58: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

58

Generic lambdas / functions

auto f = [](auto a){ return a * a; };

Page 59: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

59

auto f = [](auto a){ return a * a; };

auto f(auto a) { // Generic *functions* – OK since C++20 :) return a * a; }

Generic lambdas / functions

Page 60: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

60

template <typename T> void f(std::vector<T> vector) { // ... }

Generic lambdas / functions

Page 61: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

61

template <typename T> void f(std::vector<T> vector) { // ... }

// C++20: auto f = []<typename T>(std::vector<T> vector) { // ... };

Generic lambdas / functions

Page 62: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

62

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 63: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

63

Non-type template parameters (NTTPs)

Page 64: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

64

Non-type template parameters (NTTPs)

template <int size> struct Widget { std::array<int, size> a; };

Page 65: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

65

Non-type template parameters (NTTPs)

template <int size> struct Widget { std::array<int, size> a; };

Page 66: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

66

C++20: floating-point NTTPs

template <double x> struct Filter { std::array<double, 2> coefficients = {x, 0.5 * x * x}; // stuff... };

Page 67: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

67

C++20: class-type NTTPs

struct Coefficients { double x; double y; };

Page 68: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

68

C++20: class-type NTTPs

struct Coefficients { double x; double y; };

template <Coefficients coeffs> struct Filter { // stuff :) };

Page 69: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

69

C++20: class-type NTTPs

struct Coefficients { double x; double y; };

template <Coefficients coeffs> struct Filter { // stuff :) };

constexpr Filter<Coefficients{1, 0.125}> f;

Page 70: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

70

CTAD

Page 71: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

71

CTAD

std::vector v = {1, 2, 3}; // std::vector<int>

Page 72: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

72

CTAD

std::vector v = {1, 2, 3}; // std::vector<int>

std::tuple t = {42, 0.5, true}; // std::tuple<int, double, bool>

Page 73: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

73

CTAD

std::vector v = {1, 2, 3}; // std::vector<int>

std::tuple t = {42, 0.5, true}; // std::tuple<int, double, bool>

std::scoped_lock lock(rtmutex); // std::scoped_lock<std::recursive_timed_mutex>

Page 74: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

74

C++20 adds:

– CTAD for aggregates – CTAD for alias templates

Page 75: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

75

template <typename T, typename U> struct aggr_pair { T t; U u; };

aggr_pair p = {1, true}; // Error: no deduction candidate found

C++17

Page 76: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

76

template <typename T, typename U> struct aggr_pair { T t; U u; };

template <typename T, typename U> aggr_pair(T, U) -> aggr_pair<T, U>;

aggr_pair p = {1, true}; // OK

C++17

Page 77: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

77

template <typename T, typename U> struct aggr_pair { T t; U u; };

template <typename T, typename U> aggr_pair(T, U) -> aggr_pair<T, U>;

aggr_pair p = {1, true}; // OK

C++17 C++20template <typename T, typename U> struct aggr_pair { T t; U u; };

aggr_pair p = {1, true}; // OK

Page 78: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

78

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

C++17

Page 79: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

79

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

template<typename... Bases> overloaded(Bases...) -> overloaded<Bases...>;

C++17

Page 80: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

80

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

template<typename... Bases> overloaded(Bases...) -> overloaded<Bases...>;

overloaded printer = { [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const char* arg) { std::cout << std::quoted(arg) << ' '; } };

C++17

Page 81: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

template<typename... Bases> overloaded(Bases...) -> overloaded<Bases...>;

overloaded printer = { [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const char* arg) { std::cout << std::quoted(arg) << ' '; } };

int main() { printer("Hello, World!"); }

81

C++17

Page 82: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

82

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

template<typename... Bases> overloaded(Bases...) -> overloaded<Bases...>;

overloaded printer = { [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const char* arg) { std::cout << std::quoted(arg) << ' '; } };

int main() { printer("Hello, World!"); }

C++17

Page 83: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

template<typename... Bases> struct overloaded : Bases... { using Bases::operator()...; };

overloaded printer = { [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const char* arg) { std::cout << std::quoted(arg) << ' '; } };

int main() { printer("Hello, World!"); }

83

C++20

Page 84: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

84

namespace pmr { template <class T> using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>; }

C++17std::pmr::vector<int> v{1, 2, 3};

Page 85: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

85

namespace pmr { template <class T> using vector = std::vector<T, std::pmr::polymorphic_allocator<T>>; }

C++17 C++20std::pmr::vector<int> v{1, 2, 3}; std::pmr::vector v{1, 2, 3};

Page 86: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

86

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 87: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

87

In C++20, in a constexpr function you can:

– have a try-block – have an unevaluated asm block – use a union – call virtual functions – dynamic_cast and typeid – new and delete

Page 88: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

88

Daveed Vandevoorde “C++ Constants” C++Now 2019 keynote

Louis Dionne "Compile-time programming and reflection in C++20 and beyond” CppCon 2018 talk

Page 89: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

89

“running” code at compile time

int square(int i) { return i * i; }

Page 90: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

90

“running” code at compile time

constexpr int square(int i) { return i * i; }

square(3); // compile time square(x); // runtime

Page 91: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

consteval int square(int i) { return i * i; }

square(3); // compile time square(x); // Error - x is not a compile-time constant!

91

“running” code at compile time

Page 92: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

92

compile time or runtime?

int square(int i) { return __magic_fast_square(i); // contains runtime magic }

square(3); // runtime, fast magic square(x); // runtime, fast magic

Page 93: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

93

compile time or runtime?

constexpr int square(int i) { return i * i; }

square(3); // compile time square(x); // runtime, no fast magic :(

Page 94: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

94

compile time or runtime?

constexpr int square(int i) { if (std::is_constant_evaluated()) { return i * i; } else { return __magic_fast_square(i); } }

square(3); // compile time square(x); // runtime, fast magic :)

Page 95: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

constexpr int square(int i) { if (std::is_constant_evaluated()) { return i * i; } else { return __magic_fast_square(i); } }

square(3); // compile time square(x); // runtime, fast magic :)

95

compile time or runtime?

Page 96: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

96

1 Initialisation 2 Structured bindings 3 Lambdas 4 Templates 5 constexpr 6 Miscellaneous

Page 97: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

97

template <typename Container> auto findFirstValid(const Container& c) -> Container::iterator { return std::find_if(c.begin(), c.end(), [](auto elem){ return elem.is_valid(); }); }

Page 98: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

98

template <typename Container> auto findFirstValid(const Container& c) -> Container::const_iterator { return std::find_if(c.begin(), c.end(), [](auto elem){ return elem.is_valid(); }); }

// Error: missing 'typename' prior to dependent type name ‘Container::const_iterator'

Page 99: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

99

template <typename Container> auto findFirstValid(const Container& c) -> Container::const_iterator { return std::find_if(c.begin(), c.end(), [](auto elem){ return elem.is_valid(); }); }

// OK in C++20 :)

Page 100: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

100

New attributes in C++20

Page 101: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

101

– [[likely]], [[unlikely]]

New attributes in C++20

Page 102: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

102

– [[likely]], [[unlikely]] – [[no_unique_address]]

New attributes in C++20

Page 103: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

103

– [[likely]], [[unlikely]] – [[no_unique_address]] – [[nodiscard]] on constructors

New attributes in C++20

Page 104: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

104

– [[likely]], [[unlikely]] – [[no_unique_address]] – [[nodiscard]] on constructors – [[nodiscard(“can have a message”)]]

New attributes in C++20

Page 105: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

enum class rgba_color_channel { red, green, blue, alpha };

105

Using enum

Page 106: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

enum class rgba_color_channel { red, green, blue, alpha };

std::string_view to_string(rgba_color_channel channel) { switch (channel) { case rgba_color_channel::red: return "red"; case rgba_color_channel::green: return "green"; case rgba_color_channel::blue: return "blue"; case rgba_color_channel::alpha: return "alpha"; } }

106

Using enum

Page 107: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

107

Using enum

enum class rgba_color_channel { red, green, blue, alpha };

std::string_view to_string(rgba_color_channel channel) { switch (channel) { case rgba_color_channel::red: return "red"; case rgba_color_channel::green: return "green"; case rgba_color_channel::blue: return "blue"; case rgba_color_channel::alpha: return "alpha"; } }

Page 108: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

enum class rgba_color_channel { red, green, blue, alpha };

std::string_view to_string(rgba_color_channel channel) { switch (channel) { using enum rgba_color_channel;

case red: return "red"; case green: return "green"; case blue: return "blue"; case alpha: return "alpha"; } }

108

Using enum

Page 109: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

enum class Suit { diamonds, hearts, spades, clubs };

class Card { using enum Suit; Suit suit = spades; };

109

Using enum

Page 110: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

110

Built-in UTF-8 char type

int main() { const char* str = u8"🌈❤"; // C++17... }

Page 111: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

111

Built-in UTF-8 char type

int main() { const char* str = u8"🌈❤"; // compile error in C++20! }

Page 112: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

112

Built-in UTF-8 char type

int main() { const char8_t* str = u8"🌈❤"; }

Page 113: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

we are here

Page 114: C++20: The small thingsC++20: pack expansion allowed in lambda init capture. 52 – Lambdas are allowed in unevaluated contexts – Lambdas (without captures) are default-constructible

Timur Doumler

MeetingC++ 14 November 2019

C++20: The small things

@timur_audio

Version 1.3