C++ Library Extensions 2022.12.09
To help learn modern C++ programming
018-std_ref.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2
3/*
4 We will first learn how to use std::ref().
5*/
6
9
10template<typename Type>
11void increment(Type n)
12{
13 ++n;
14}
15
16template<typename Type>
17void decrement(Type&& n)
18{
19 --n;
20}
21
23{
24 int n = 5;
25
26 stream << "Before calling increment(n): " << n << endl;
27 increment(n);
28 stream << "After calling increment(n): " << n << endl;
29
30 stream << "Before calling increment<int&>(n): " << n << endl;
31 increment<int&>(n);
32 stream << "After calling increment<int&>(n): " << n << endl;
33
34 stream << "Before calling increment(std::ref(n)): " << n << endl;
36 stream << "After calling increment(std::ref(n)): " << n << endl;
37
38 // thread t runs immediately
39 std::thread t{ increment<int>, n};
40
41 t.join(); // wait until thread t returns
42
43 stream << "After the thread t finished: " << n << endl;
44
45 // thread s runs immediately
46 std::thread s{ increment<int&>, std::ref(n)};
47
48 s.join(); // wait until thread t returns
49
50 stream << "After the thread s finished: " << n << endl;
51
52 /*
53 But most of C++ Standard Library functions are
54 built using forwarding references.
55 */
56
57 // thread u runs immediately
58 std::thread u{ decrement<int& /* template parameter argument */>,
59 std::ref(n) // function-call argument
60 };
61
62 u.join(); // wait until thread t returns
63
64 stream << "After the thread u finished: " << n << endl;
65
66 // std::thread v { [](auto& arg){ return arg *= arg; }, std::ref(n)};
67
68 // this works in C++2a Standard, as of today, May 25, 2019
69 // only GNU g++ compiler supports
70 // g++ -std=c++2a 018-std_ref.cpp
71 // std::thread v { []<typename Type>(Type&& arg) { return arg *= arg;},
72 // // C++2a Standard will introduce template parameter specification
73 // // at lambda expression, https://en.cppreference.com/w/cpp/language/lambda
74 // std::ref(n)};
75
76 // v.join(); // wait until thread v returns
77
78 // stream << "After the thread v finished: " << n << endl;
79
80 // thread w runs immediately
81 std::thread w{ [](auto&& arg){ return arg *= arg; },
82 std::ref(n) // function-call argument
83 };
84
85 w.join(); // wait until thread t returns
86
87 stream << "After the thread w finished: " << n << endl;
88
89}
90
91template<typename Type>
93{
94 private:
95 Type *m_ptr;
96
97 public:
98
99 template<typename UType>
100 reference_wrapper(UType&& val)
101 {
102 Type& lvalue = std::forward<UType>(val);
103
104 // this->m_ptr = &lvalue;
105 // I will talk more about std::addressof() in some future sessions
106 // it returns the address of object (or lvalue)
107 this->m_ptr = std::addressof(lvalue);
108 }
109
110 operator Type&() const noexcept
111 { return *this->m_ptr; }
112
113 Type& get() const noexcept
114 { return *this->m_ptr; }
115};
116
117template<typename Type>
118reference_wrapper<Type> ref(Type& val) noexcept
119{
120 return reference_wrapper<Type>(val);
121}
122
124{
125 int n = 5;
126
127 stream << "Before calling increment(n): " << n << endl;
128 increment(n);
129 stream << "After calling increment(n): " << n << endl;
130
131 stream << "Before calling increment<int&>(n): " << n << endl;
132 increment<int&>(n);
133 stream << "After calling increment<int&>(n): " << n << endl;
134
135 stream << "Before calling increment(std::ref(n)): " << n << endl;
136 increment(ref(n));
137 stream << "After calling increment(std::ref(n)): " << n << endl;
138
139 // thread t runs immediately
140 std::thread t{ increment<int>, n};
141
142 t.join(); // wait until thread t returns
143
144 stream << "After the thread t finished: " << n << endl;
145
146 // thread s runs immediately
147 std::thread s{ increment<int&>, ref(n)};
148
149 s.join(); // wait until thread t returns
150
151 stream << "After the thread s finished: " << n << endl;
152
153 /*
154 But most of C++ Standard Library functions are
155 built using forwarding references.
156 */
157
158 // thread u runs immediately
159 std::thread u{ decrement<int& /* template parameter argument */>,
160 ref(n) // function-call argument
161 };
162
163 u.join(); // wait until thread t returns
164
165 stream << "After the thread u finished: " << n << endl;
166
167 // std::thread v { [](auto& arg){ return arg *= arg; }, std::ref(n)};
168
169 // this works in C++2a Standard, as of today, May 25, 2019
170 // only GNU g++ compiler supports
171 // g++ -std=c++2a 018-std_ref.cpp
172 // std::thread v { []<typename Type>(Type&& arg) { return arg *= arg;},
173 // // C++2a Standard will introduce template parameter specification
174 // // at lambda expression, https://en.cppreference.com/w/cpp/language/lambda
175 // std::ref(n)};
176
177 // v.join(); // wait until thread v returns
178
179 // stream << "After the thread v finished: " << n << endl;
180
181 // thread w runs immediately
182 std::thread w{ [](auto&& arg){ return arg *= arg; },
183 ref(n) // function-call argument
184 };
185
186 w.join(); // wait until thread t returns
187
188 stream << "After the thread w finished: " << n << endl;
189
190}
191
192
193int main()
194{
195 // examples_for_std_ref();
197}
void examples_for_custom_ref()
tpf::sstream stream
Definition: 018-std_ref.cpp:7
void decrement(Type &&n)
Definition: 018-std_ref.cpp:17
void increment(Type n)
Definition: 018-std_ref.cpp:11
void examples_for_std_ref()
Definition: 018-std_ref.cpp:22
auto endl
Definition: 018-std_ref.cpp:8
int main()
reference_wrapper< Type > ref(Type &val) noexcept
Type & get() const noexcept
reference_wrapper(UType &&val)
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.