Solutions
42 |
43 | ```cpp
44 | int main() {
45 | constexpr auto l1 = [] {};
46 | constexpr auto l2 = [] mutable{};
47 | constexpr auto l3 = [] mutable constexpr {};
48 | constexpr auto l4 = [] mutable consteval {};
49 | constexpr auto l5 = [] mutable consteval {};
50 | constexpr auto l6 = [] -> int { return {}; };
51 | constexpr auto l7 = [] -> auto { return 0; };
52 | constexpr auto l8 = [] {};
53 | constexpr auto l9 = [] {};
54 | constexpr auto l10 = [] mutable {};
55 | constexpr auto l11 = [] noexcept {};
56 | }
57 | ```
58 |
59 | > https://godbolt.org/z/ozro3cr53
60 |
--------------------------------------------------------------------------------
/tips/230.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added `if consteval`?**
4 |
5 | * http://wg21.link/p1938
6 |
7 |
Example
8 |
9 | ```cpp
10 | #include
11 |
12 | consteval int f(int i) { return i; }
13 |
14 | constexpr int g(int i) {
15 | if consteval {
16 | return f(i) + 1; // ok: immediate function context
17 | } else {
18 | return 42;
19 | }
20 | }
21 |
22 | consteval int h(int i) {
23 | return f(i) + 1; // ok: immediate function context
24 | }
25 |
26 | static_assert(42 + 1 == h(42));
27 |
28 | int main() {
29 | int i = 42;
30 | //h(i); // error: the value of 'i' is not usable in a constant expression
31 | assert(42 == g(i));
32 | }
33 | ```
34 |
35 | > https://godbolt.org/z/rjeodeMoP
36 |
37 |
Puzzle
38 |
39 | * **Can you implement a `add_or_sub` algorithm which adds `args…` to `N` in consteval context and subs `args...` from `N` otherwise?**
40 |
41 | ```cpp
42 | template
43 | constexpr auto add_or_sub = [](const auto... args); // TODO
44 |
45 | int main() {
46 | using namespace boost::ut;
47 |
48 | "add or sub test"_test = [] {
49 | should("add in consteval context") = [] {
50 | expect(constant<0_i == add_or_sub<0>()>);
51 | expect(constant<1_i == add_or_sub<0>(1)>);
52 | expect(constant<2_i == add_or_sub<1>(1)>);
53 | expect(constant<4_i == add_or_sub<1>(1, 2)>);
54 | expect(constant<16_i == add_or_sub<2>(3, 4, 7)>);
55 | };
56 |
57 | should("sub in non-consteval context") = [] {
58 | expect(0_i == add_or_sub<0>());
59 | expect(-1_i == add_or_sub<0>(1));
60 | expect(0_i == add_or_sub<1>(1));
61 | expect(-2_i == add_or_sub<1>(1, 2));
62 | expect(-12_i == add_or_sub<2>(3, 4, 7));
63 |
64 | const auto i = 42;
65 | expect(-44_i == add_or_sub<>(2, i));
66 |
67 | auto x = 7;
68 | expect(-51_i == add_or_sub<1>(1, x, 2, i));
69 | };
70 | };
71 | }
72 | ```
73 |
74 | > https://godbolt.org/z/xssv8MY4W
75 |
76 |
Solutions
77 |
78 | ```cpp
79 | template
80 | constexpr auto add_or_sub = [](const auto... args) {
81 | if consteval {
82 | return (N + ... + args);
83 | } else {
84 | return (N - ... - args);
85 | }
86 | };
87 | ```
88 |
89 | > https://godbolt.org/z/8vqoPb5dT
90 |
91 | ```cpp
92 | template
93 | constexpr auto add_or_sub = [](const auto... args) {
94 | const auto sum_of_args = (args + ... + 0);
95 | if consteval {
96 | return N + sum_of_args;
97 | } else {
98 | return N - sum_of_args;
99 | }
100 | };
101 | ```
102 |
103 | > https://godbolt.org/z/5xerzMjq3
104 |
--------------------------------------------------------------------------------
/tips/232.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that different overloads can have different specifiers?**
4 |
5 | * http://eel.is/c++draft/dcl.spec.general
6 |
7 |
Example
8 |
9 | ```cpp
10 | constexpr auto foo(auto) { return 42; }
11 | consteval auto foo(auto f) requires requires { f.value; } { return f.value; }
12 |
13 | int main(int argc, char**) {
14 | std::cout << foo(argc); // prints 42
15 |
16 | constexpr struct {
17 | int value{88};
18 | } v;
19 |
20 | std::cout << foo(v); // prints 88
21 | }
22 | ```
23 |
24 | > https://godbolt.org/z/a9sKb177j
25 |
26 |
Puzzle
27 |
28 | * **Can you implement a function f which for { 0 args: is run-time - returns 42; 1 arg: is run/compile-time, returns arg; >1 args: is compile-time, returns sum of args... }**
29 |
30 | ```cpp
31 | auto f(...); // TODO
32 |
33 | template auto is_compile_time() {}
34 |
35 | int main() {
36 | using namespace boost::ut;
37 |
38 | "run-time call"_test = [] {
39 | expect(42_i == f());
40 | expect(not [](auto... ts) { return requires { is_compile_time(); }; }());
41 | };
42 |
43 | "constexpr call"_test = [] {
44 | "compile-time call"_test = [] {
45 | expect(constant<42_i == f(42)>);
46 | expect(requires { is_compile_time(); });
47 |
48 | constexpr auto i = 43;
49 | expect(constant<43_i == f(43)>);
50 | };
51 |
52 | "run-time call"_test = [] {
53 | auto i = 44;
54 | expect(44_i == f(i));
55 | };
56 | };
57 |
58 | "consteval call"_test = [] {
59 | expect(constant<3_i == f(1, 2)>);
60 | expect(constant<6_i == f(1, 2, 3)>);
61 | auto i = 1;
62 | //f(42, i); // should not compile
63 | };
64 | }
65 | ```
66 |
67 | > https://godbolt.org/z/EWK873qfv
68 |
69 |
Solutions
70 |
71 | ```cpp
72 | auto f() { return 42; }
73 | constexpr auto f(auto v) { return v; }
74 | template consteval auto f(Args... args) { return (0 + ... + args); }
75 | ```
76 |
77 | > https://godbolt.org/z/6hM3nbabv
78 |
79 |
80 | ```cpp
81 | auto f() { return 42; }
82 | constexpr auto f(auto arg) { return arg; }
83 | consteval auto f(auto... args) { return (... + args); }
84 | ```
85 |
86 | > https://godbolt.org/z/qdf3z1Khr
87 |
88 | ```cpp
89 | auto f() { return 42; }
90 | constexpr auto f(auto value) { return value; }
91 | consteval auto f(auto... values) requires (sizeof...(values) > 1) { return (... + values); }
92 | ```
93 |
94 | > https://godbolt.org/z/8o3WYG8ze
95 |
--------------------------------------------------------------------------------
/tips/233.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++20 made `typename` more optional?**
4 |
5 | * http://wg21.link/p0634
6 |
7 |
Example
8 |
9 | ```cpp
10 | template /*typename*/T::type return_type(); // okay
11 | template void void_parameter(/*typename*/T::type); // error: variable or field 'parameter' declared void
12 | template auto auto_parameter(/*typename*/T::type); // okay
13 |
14 | template
15 | struct traits {
16 | using type = /*typename*/ T::type; // okay
17 | };
18 | ```
19 |
20 | > https://godbolt.org/z/oMMzfjeKv
21 |
22 |
Puzzle
23 |
24 | * **Can you add/remove required/unnecessary `typename's`**
25 |
26 | ```cpp
27 | template
28 | struct traits {
29 | using type = typename T::type;
30 | };
31 |
32 | template
33 | struct s : typename T::type {};
34 |
35 | template typename T::type f1();
36 | template auto f2() -> typename T::type;
37 | auto f3(auto t) -> typename decltype(t)::type;
38 |
39 | template auto f4(typename T::type);
40 | template bool f5(typename T::type);
41 | template void f6(T::type);
42 | template auto f7(T::type) -> void;
43 | auto f8(auto t) -> typename decltype(t)::type;
44 | ```
45 |
46 | > https://godbolt.org/z/EEeTh5TWP
47 |
48 |
Solutions
49 |
50 | ```cpp
51 | template
52 | struct traits {
53 | using type = T::type;
54 | };
55 |
56 | template
57 | struct s : T::type {};
58 |
59 | template T::type f1();
60 | template auto f2() -> T::type;
61 | auto f3(auto t) -> decltype(t)::type;
62 |
63 | template auto f4(T::type);
64 | template bool f5(T::type);
65 | template void f6(typename T::type);
66 | template auto f7(typename T::type) -> void;
67 | auto f8(auto t) -> decltype(t)::type;
68 | ```
69 |
70 | > https://godbolt.org/z/nMsqeaev8
71 |
--------------------------------------------------------------------------------
/tips/234.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know about function-try-block and that exceptions caught inside that block are implicitly rethrown?**
4 |
5 | * http://eel.is/c++draft/except.pre#nt:function-try-block
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct foo {
11 | foo() { throw 0; }
12 | };
13 |
14 | struct bar {
15 | bar() try : foo_{} {
16 | // constructor body
17 | }
18 | catch (...)
19 | {
20 | // exceptions from the initializer list are caught here
21 | // but also re-thrown after this block (unless the program is aborted)
22 | }
23 |
24 | private:
25 | foo foo_;
26 | };
27 |
28 | int main() try {
29 | bar b{};
30 | }
31 | catch(...) {
32 | // okay, exception cought here!
33 | }
34 | ```
35 |
36 | > https://godbolt.org/z/Y4efK573f
37 |
38 |
Puzzle
39 |
40 | * **Can you implement `foo`'s constructor which initializes `Ts...` and sets `exception` to true if any exception is thrown and rethrows it?**
41 |
42 | ```cpp
43 | template
44 | struct ctor_except {
45 | ctor_except() { throw TException{}; }
46 | };
47 |
48 | template
49 | struct foo : Ts... {
50 | explicit(true) foo(bool& exception); // TODO
51 | };
52 |
53 | int main() {
54 | using namespace boost::ut;
55 |
56 | "function-try-block"_test = [] {
57 | bool exception{false};
58 | struct bar { };
59 |
60 | should("not set exception with empty list") = [=] {
61 | expect(nothrow([&]{ foo<>{mut(exception)}; }) and not exception);
62 | };
63 |
64 | should("not set exception with non-throwing types") = [=] {
65 | expect(nothrow([&]{ foo{mut(exception)}; }) and not exception);
66 | };
67 |
68 | should("catch exception if thrown from within the constructor") = [=] {
69 | expect(throws([&]{ foo>{mut(exception)}; }) and exception);
70 | };
71 |
72 | should("catch exception if thrown from within the constructor with muliple types") = [=] {
73 | expect(throws([&]{ foo>{mut(exception)}; }) and exception);
74 | };
75 | };
76 | }
77 | ```
78 |
79 | > https://godbolt.org/z/s3MzE8xM9
80 |
81 |
Solutions
82 |
83 | ```cpp
84 | template
85 | struct foo : Ts... {
86 | explicit(true) foo (bool& exception) try : Ts{}... {
87 | } catch (...) {
88 | exception = true;
89 | }
90 | };
91 | ```
92 |
93 | > https://godbolt.org/z/8Yxr7WbsM
94 |
95 | ```cpp
96 | template
97 | struct foo : Ts... {
98 | explicit(true) foo(bool& exception) try : Ts()... {
99 | exception = false;
100 | } catch(...) {
101 | exception = true;
102 | }
103 | };
104 | ```
105 |
106 | > https://godbolt.org/z/dnhcjsYjK
107 |
--------------------------------------------------------------------------------
/tips/237.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know about C++2X proposal for the Circle Meta-model for compilation-time meta-programming?**
4 |
5 | * http://wg21.link/p2062
6 | * https://github.com/seanbaxter/circle/blob/master/reflection/README.md
7 |
8 |
Example
9 |
10 | ```cpp
11 | #include
12 |
13 | auto main() -> int {
14 | std::puts("Hello world"); // during run-time
15 | @meta std::puts("Hello circle"); // during compilation-time
16 | }
17 | ```
18 |
19 | ```sh
20 | Hello circle
21 | ASM generation compiler returned: 0
22 | Hello circle
23 | Execution build compiler returned: 0
24 | Program returned: 0
25 | Hello world
26 | ```
27 |
28 | > https://godbolt.org/z/bo48q1oWW
29 |
30 |
Puzzle
31 |
32 | * **Can you implement `to_tuple_with_names` which returns `named` fields based on Circle Meta-model?**
33 |
34 | ```cpp
35 | template
36 | struct named {
37 | T value{};
38 | std::string_view name{};
39 | };
40 |
41 | template auto to_tuple_with_names(const T& t); // TODO
42 |
43 | int main() {
44 | {
45 | struct empty { };
46 |
47 | const auto & t = to_tuple_with_names(empty{});
48 |
49 | expect(0 == std::tuple_size_v>);
50 | }
51 |
52 | {
53 | struct trade {
54 | std::int32_t price{42};
55 | };
56 |
57 | const auto & t = to_tuple_with_names(trade{});
58 |
59 | expect(1 == std::tuple_size_v>);
60 | expect(42 == std::get<0>(t).value and "price" == std::get<0>(t).name);
61 | }
62 |
63 | {
64 | struct trade {
65 | std::int32_t price{42};
66 | std::uint32_t quantity{1'000u};
67 | };
68 |
69 | const auto & t = to_tuple_with_names(trade{});
70 |
71 | expect(2 == std::tuple_size_v>);
72 | expect(42 == std::get<0>(t).value and "price" == std::get<0>(t).name);
73 | expect(1'000u == std::get<1>(t).value and "quantity" == std::get<1>(t).name);
74 | };
75 | }
76 | ```
77 |
78 | > https://godbolt.org/z/sEhYvas7o
79 |
80 |
Solutions
81 |
82 | ```cpp
83 | template auto to_tuple_with_names(const T& t) {
84 | std::tuple...> result;
85 | result...[:] = { t...[:], @member_names(T) } ...;
86 | return result;
87 | }
88 | ```
89 |
90 | > https://godbolt.org/z/cbdofa9MY
91 |
92 | ```cpp
93 | template [[nodiscard]] auto to_tuple_with_names(const T& t) {
94 | constexpr auto to_tuple_with_names = [](const TValues&... values) {
95 | return [&](const auto&... names) {
96 | return std::make_tuple(named{values, names}...);
97 | };
98 | };
99 | return to_tuple_with_names(t.@member_values()...)(@member_names(T)...);
100 | }
101 | ```
102 |
103 | > https://godbolt.org/z/EzhbT9q8P
104 |
105 | ```cpp
106 | template auto to_tuple_with_names(const T& t) {
107 | std::tuple...> result;
108 | @meta for(int i = 0; i < @member_count(T); ++i) {
109 | std::get(result) = { @member_value(t, i), @member_name(T, i) };
110 | }
111 | return result;
112 | }
113 | ```
114 |
115 | ```cpp
116 | template auto to_tuple_with_names(const T& t) {
117 | return std::make_tuple(named<@member_types(T)>{@member_values(t), @member_names(T)}...);
118 | }
119 | ```
120 |
121 | > https://godbolt.org/z/x9nWbWaEv
122 |
123 | ```cpp
124 | template
125 | [[nodiscard]] constexpr auto to_tuple_with_names(const T &t) {
126 | return std::make_tuple(
127 | named<@member_types(T)>{t.@member_values(), @member_names(T)}...);
128 | }
129 | ```
130 |
131 | > https://godbolt.org/z/a1GK46e6n
132 |
133 | ```cpp
134 | template auto get_member( T const & obj)
135 | {
136 | return named{ obj.@member_value(I), @member_name(T, I) };
137 | }
138 | template auto to_tuple_with_names(const T& t){
139 | const int N = @member_count(T);
140 | return [&]( std::integer_sequence const & )
141 | {
142 | return std::make_tuple(get_member(t)...);
143 | }(std::make_integer_sequence{} );
144 | };
145 | ```
146 |
147 | > https://godbolt.org/z/8rch9eTaW
148 |
--------------------------------------------------------------------------------
/tips/239.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that Circle Meta-model allows to convert string to a type?**
4 |
5 | * http://wg21.link/p2062
6 | * https://github.com/seanbaxter/circle/blob/master/reflection/README.md
7 |
8 |
Example
9 |
10 | ```cpp
11 | int main() {
12 | @meta std::string type = "int";
13 | @type_id(type) i = 42; // string -> type
14 | return i; // returns int = 4
15 | }
16 | ```
17 |
18 | > https://godbolt.org/z/138zW9PvT
19 |
20 |
Puzzle
21 |
22 | * **Can you implement `strings_to_tuple` function which converts given strings into a `std::tuple` of them?**
23 |
24 | ```cpp
25 | template
26 | constexpr auto strings_to_tuple(Ts...); // TODO
27 |
28 | struct foo {
29 | int id{};
30 | };
31 |
32 | int main() {
33 | using namespace boost::ut;
34 |
35 | "string types to tuple"_test = [] {
36 | "empty"_test = [] {
37 | auto ts = strings_to_tuple();
38 | expect(std::is_same_v, decltype(ts)>);
39 | };
40 |
41 | "simple types"_test = [] {
42 | auto ts = strings_to_tuple([]{return "int";}, []{return "double";});
43 | std::get<0>(ts) = 4;
44 | std::get<1>(ts) = 2.;
45 | expect(4_i == std::get<0>(ts) and 2._d == std::get<1>(ts));
46 | };
47 |
48 | "mix types"_test = [] {
49 | auto ts = strings_to_tuple([]{return "unsigned";}, []{return "foo";},[]{return "int";});
50 | std::get<0>(ts) = 1.;
51 | std::get<1>(ts).id = 2;
52 | std::get<2>(ts) = 3;
53 | expect(1_u == std::get<0>(ts) and 2_i == std::get<1>(ts).id and 3_i == std::get<2>(ts));
54 | };
55 | };
56 | }
57 | ```
58 |
59 | > https://godbolt.org/z/PsEjEKfvd
60 |
61 |
Solutions
62 |
63 | ```cpp
64 | template
65 | constexpr auto strings_to_tuple(Ts...) {
66 | return std::tuple<(@type_id(Ts{}()))...>{};
67 | }
68 | ```
69 |
70 | > https://cpp-tip-of-the-week.godbolt.org/z/xzjP1fWbx
71 |
72 | ```cpp
73 | template
74 | constexpr auto strings_to_tuple(Ts...args )
75 | {
76 | auto toTypedObj = []( auto arg ){
77 | constexpr const char * tName = arg();
78 | return @type_id(tName){};
79 | };
80 | return std::make_tuple(toTypedObj(args)...);
81 | }
82 | ```
83 |
84 | > https://godbolt.org/z/hhcT76vTh
85 |
86 | ```cpp
87 | constexpr auto strings_to_tuple(Ts...) {
88 | return std::tuple<@type_id(Ts{}())...>{};
89 | }
90 | ```
91 |
92 | > https://godbolt.org/z/rej46v8a9
93 |
94 | ```cpp
95 | template
96 | constexpr auto strings_to_tuple(Ts ...) {
97 | return std::make_tuple(@type_id(Ts{}()){}...);
98 | }
99 | ```
100 |
101 | > https://godbolt.org/z/4M3M7c5Mz
102 |
--------------------------------------------------------------------------------
/tips/241.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know about different ways of accessing C-style arrays by index?**
4 |
5 | * http://eel.is/c++draft/dcl.array#def:array
6 |
7 |
Example
8 |
9 | ```cpp
10 | int main() {
11 | constexpr int array[] = {1, 2, 3};
12 | assert(2[array] == array[2]);
13 | assert(*(array+1) == array[1]);
14 | }
15 | ```
16 |
17 | > https://godbolt.org/z/5PnPzWvW8
18 |
19 |
Puzzle
20 |
21 | * **Can you implement `sum_n` which sums the first N numbers from the array using an altenative access syntax?**
22 |
23 | ```cpp
24 | template
25 | /*TODO*/ auto sum_n(auto);
26 |
27 | int main() {
28 | using namespace boost::ut;
29 |
30 | "sum_n"_test = [] {
31 | should("return 0 for empty array") = [] {
32 | constexpr int array[] = {};
33 | expect(constant<0 == sum_n<0>(array)>);
34 | };
35 |
36 | should("sum N first parameters") = [] {
37 | constexpr int array[] = {1, 2, 3};
38 | expect(constant<0 == sum_n<0>(array)>);
39 | expect(constant<1 == sum_n<1>(array)>);
40 | expect(constant<3 == sum_n<2>(array)>);
41 | expect(constant<6 == sum_n<3>(array)>);
42 | };
43 | };
44 | }
45 | ```
46 |
47 | > https://godbolt.org/z/5dMrTzGo7
48 |
49 |
Solutions
50 |
51 | ```cpp
52 | template constexpr auto sum_n(auto a) {
53 | std::decay_t sum{};
54 | for (auto i = 0; i < N; ++i) {
55 | sum += i[a];
56 | }
57 | return sum;
58 | }
59 | ```
60 |
61 | > https://cpp-tip-of-the-week.godbolt.org/z/51fY56zdc
62 |
63 | ```cpp
64 | template
65 | constexpr auto sum_n(auto arr) {
66 | return [&] (std::integer_sequence) {
67 | return (0 + ... + Nth_of[arr]);
68 | }(std::make_integer_sequence{});
69 | }
70 | ```
71 |
72 | > https://godbolt.org/z/K9rcenjME
73 |
74 | ```cpp
75 | template
76 | [[nodiscard]] constexpr auto sum_n(const auto array) {
77 | return [array](std::index_sequence) {
78 | return (Is[array] + ... + 0);
79 | }(std::make_index_sequence{});
80 | }
81 | ```
82 |
83 | > https://godbolt.org/z/cjo8MovY8
84 |
85 | ```cpp
86 | template
87 | auto constexpr sum_n(auto arr) {
88 | double sum = 0;
89 | for(uint32_t i=0; i https://godbolt.org/z/Y6GxMMjx6
96 |
97 | ```cpp
98 | template
99 | auto constexpr get_i(auto const & array)
100 | {
101 | if constexpr (I % 3 == 0 )
102 | return array[I];
103 | else if constexpr (I % 3 == 1)
104 | return I[array];
105 | else
106 | return *(array + I );
107 | }
108 | template
109 | auto constexpr sum_n(auto const & array)
110 | {
111 | return [&]( std::index_sequence const & )
112 | {
113 | return (get_i(array) + ... + 0 );
114 | }(std::make_index_sequence());
115 | }
116 | ```
117 |
118 | > https://godbolt.org/z/cx4nfGhvz
119 |
120 | ```cpp
121 | template
122 | constexpr auto sum_n(const auto& array) {
123 | return [&](std::index_sequence) {
124 | return (0 + ... + Ith_index_of[array]);
125 | }(std::make_index_sequence{});
126 | }
127 | ```
128 |
129 | > https://godbolt.org/z/d3Gcaq7Pn
130 |
131 | ```cpp
132 | template
133 | [[nodiscard]] constexpr auto sum_n(const auto array) {
134 | return [array](std::index_sequence) {
135 | return (Is[array] + ... + 0);
136 | }(std::make_index_sequence{});
137 | }
138 | ```
139 |
140 | > https://godbolt.org/z/3nf6aKM4r
141 |
--------------------------------------------------------------------------------
/tips/247.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that `Deducing this` proposal has been voted out into C++23?**
4 |
5 | * http://wg21.link/p0847
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct foo {
11 | auto bar(bool b) { return b; }
12 |
13 | // deducing this
14 | auto baz(this foo const & self, bool b) { return not b; }
15 | };
16 |
17 | static_assert(foo{}.bar(true));
18 | static_assert(not foo{}.baz(true));
19 |
20 | static_assert(not foo{}.bar(false));
21 | static_assert(foo{}.baz(false));
22 | ```
23 |
24 | > https://circle.godbolt.org/z/TMc63G5Tf
25 |
26 |
Puzzle
27 |
28 | * **Can you implement sum which adds args... by using a recursive lambda with deduced this?**
29 |
30 | ```cpp
31 | constexpr auto sum = [](...); // TODO
32 |
33 | static_assert(0 == sum());
34 | static_assert(1 == sum(1));
35 | static_assert(3 == sum(1, 2));
36 | static_assert(6 == sum(1, 2, 3));
37 | static_assert(6 == sum(2, 3, 1));
38 | ```
39 |
40 | > https://circle.godbolt.org/z/j8a7oc8nT
41 |
42 |
Solutions
43 |
44 | ```cpp
45 | constexpr auto sum = [](this const auto& self, auto... args) {
46 | if constexpr (sizeof...(args) == 0) {
47 | return 0;
48 | } else {
49 | return [&](auto arg, auto... args) { return arg + self(args...); }(args...);
50 | }
51 | };
52 | ```
53 |
54 | > https://circle.godbolt.org/z/Gf7PdP64G
55 |
56 | ```cpp
57 | constexpr auto sum = [](this auto self, auto ... args)
58 | {
59 | auto peelArg = [&](auto arg, auto ...args) {
60 | return arg + self(args...);
61 | };
62 |
63 | if constexpr (sizeof...(args) == 0)
64 | return 0;
65 | else
66 | return peelArg(args...);
67 | };
68 |
69 | ```
70 |
71 | > https://circle.godbolt.org/z/vnrTEnGcr
72 |
73 | ```cpp
74 | constexpr auto sum = [](this const auto& self, const auto&... args) {
75 | if constexpr(sizeof...(args) == 0) {
76 | return 0;
77 | } else {
78 | return [self](const auto& first_arg, const auto&... remaining_args) {
79 | return first_arg + self(remaining_args...);
80 | }(args...);
81 | }
82 | };
83 |
84 | ```
85 |
86 | > https://circle.godbolt.org/z/7cz5WbTd3
87 |
88 | ```cpp
89 | constexpr auto sum = [](this auto & self, auto ... Is ){
90 | if constexpr ( (sizeof ...( Is) ) == 0 )
91 | return 0;
92 | else
93 | return [&]( auto I , auto ... Iss ) { return I + self.operator()( Iss ... ) ; }( Is...);
94 | };
95 | ```
96 |
97 | > https://circle.godbolt.org/z/7d8acTPWE
98 |
99 | ```cpp
100 | constexpr auto sum = [] (this const auto &self, auto... args) {
101 | if constexpr (sizeof...(args) >= 1) {
102 | return [=] (auto first, auto... rest) {
103 | return first + self(rest...);
104 | }(args...);
105 | }
106 |
107 | return 0;
108 | };
109 | ```
110 |
111 | > https://circle.godbolt.org/z/c4Pjb51cc
112 |
113 | ```cpp
114 | constexpr auto sum = [](this const auto& self, auto... args) {
115 | if constexpr (sizeof...(args) > 0) {
116 | return [self](const auto head, const auto... tail) {
117 | return head + self(tail...);
118 | }(args...);
119 | }
120 | return 0;
121 | };
122 | ```
123 |
124 | > https://circle.godbolt.org/z/PzzEKs14q
125 |
126 | ```cpp
127 | constexpr auto sum = [](this auto const &self, auto ...args){
128 | if constexpr ( sizeof...(args) == 0 ){
129 | return 0;
130 | } else {
131 | return [=](const auto arg, auto ... rest_of_args){
132 | return arg + self(rest_of_args...);
133 | }(args...);
134 | }
135 | };
136 | ```
137 |
138 | > https://circle.godbolt.org/z/zas389zWT
139 |
--------------------------------------------------------------------------------
/tips/249.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 allows extended init-statement with alias-declaration in the for loop?**
4 |
5 | * http://wg21.link/p2360
6 |
7 |
Example
8 |
9 | ```cpp
10 | #include
11 | #include
12 |
13 | int main() {
14 | for (using T = int; T e : {1, 2}) {
15 | std::cout << e; // prints 1,2
16 | }
17 |
18 | for (struct T { int x; int y; }; T e : {T{1,2}, T{3,4}}) {
19 | std::cout << "{" << e.x << ',' << e.y << '}'; // prints {1,2}{3,4}
20 | }
21 | }
22 | ```
23 |
24 | > https://godbolt.org/z/Y3nvPafec
25 |
26 |
Puzzle
27 |
28 | * **Can you implement an init-statement for the for loop which will add an anonymous struct {x,y} and an alias declaration T to it?**
29 |
30 | ```cpp
31 | auto print(std::ostream& os, auto... args) -> std::ostream& {
32 | for (/*TODO*/ : {T{args.first, args.second}...}) {
33 | os << '{' << e.x << ',' << e.y << '}';
34 | }
35 | return os;
36 | }
37 |
38 | int main() {
39 | using namespace boost::ut;
40 |
41 | "print"_test = [] {
42 | "empty"_test = [] {
43 | std::stringstream str{};
44 | print(str);
45 | expect(std::string_view{""} == str.str());
46 | };
47 |
48 | "single pair"_test = [] {
49 | std::stringstream str{};
50 | print(str, std::pair{1,2});
51 | expect(std::string_view{"{1,2}"} == str.str());
52 | };
53 |
54 | "multiple pairs"_test = [] {
55 | std::stringstream str{};
56 | print(str, std::pair{1,3}, std::pair{2, 4});
57 | expect(std::string_view{"{1,3}{2,4}"} == str.str());
58 | };
59 | };
60 | }
61 | ```
62 |
63 | > https://godbolt.org/z/zjWGhnGnf
64 |
65 |
Solutions
66 |
67 | ```cpp
68 | auto print(std::ostream& os, auto... args) -> std::ostream& {
69 | for (using T = struct { int x; int y; }; const T& e : std::initializer_list{T{args.first, args.second}...}) {
70 | os << '{' << e.x << ',' << e.y << '}';
71 | }
72 | return os;
73 | }
74 | ```
75 |
76 | > https://godbolt.org/z/xzd398z3n
77 |
78 | ```cpp
79 | auto print(std::ostream& os) -> std::ostream& { return os; }
80 | auto print(std::ostream& os, auto... args) -> std::ostream& {
81 | for (using T = struct { int x; int y; }; const T& e : {T{args.first, args.second}...}) {
82 | os << '{' << e.x << ',' << e.y << '}';
83 | }
84 | return os;
85 | }
86 | ```
87 |
88 | > https://godbolt.org/z/cehWYKz5a
89 |
90 | ```cpp
91 | auto print(std::ostream& os, auto... args) -> std::ostream& {
92 | for (using T = struct {int x; int y;}; const T & e : std::vector{T{args.first, args.second}...}) {
93 | os << '{' << e.x << ',' << e.y << '}';
94 | }
95 | return os;
96 | }
97 | ```
98 |
99 | > https://godbolt.org/z/3WaPGeG5b
100 |
101 | ```cpp
102 | auto print(std::ostream& os, auto... args) -> std::ostream& {
103 | for (struct T { int x; int y; }; const auto &e : std::initializer_list{{args.first, args.second}...}) {
104 | os << '{' << e.x << ',' << e.y << '}';
105 | }
106 | return os;
107 | }
108 | ```
109 |
110 | > https://godbolt.org/z/YdYsfTW1a
111 |
112 | ```cpp
113 | auto print(std::ostream& os, auto... args) -> std::ostream& {
114 | if constexpr (sizeof...(args) > 0) {
115 | for (using T = struct { int x; int y; }; auto const& e : {T{args.first, args.second}...}) {
116 | os << '{' << e.x << ',' << e.y << '}';
117 | }
118 | }
119 | return os;
120 | }
121 | ```
122 |
123 | > https://godbolt.org/z/n9reaY7hE
124 |
125 | ```cpp
126 | auto print(std::ostream& os, auto... args) -> std::ostream& {
127 | for (using T = struct { int x; int y;}; T const & e : std::array{T{args.first, args.second}...}) {
128 | os << '{' << e.x << ',' << e.y << '}';
129 | }
130 | return os;
131 | }
132 | ```
133 |
134 | > https://godbolt.org/z/aKT6ocr6c
135 |
--------------------------------------------------------------------------------
/tips/253.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++20 extends support for data time utilities?**
4 |
5 | * https://eel.is/c++draft/#time
6 |
7 |
Example
8 |
9 | ```cpp
10 | constexpr auto thanksgiving = November / 25 / 2021y;
11 |
12 | static_assert(year(2021) == thanksgiving.year());
13 | static_assert(month(11) == thanksgiving.month());
14 | static_assert(day(25) == thanksgiving.day());
15 | ```
16 |
17 | > https://godbolt.org/z/eda4d35xT
18 |
19 |
Puzzle
20 |
21 | * **Can you apply std::chrono data time utilities to verify Thanksgiving dates**?
22 |
23 | ```cpp
24 | constexpr auto thanksgiving = November / 25 / 2021y;
25 | constexpr auto cpptipday = 21d / 11 / 2021;
26 |
27 | static_assert( /*is thanksgivng a valid date?*/);
28 | static_assert(Thursday == /*what day is thanksgiving?*/);
29 | static_assert(days(4) == /*how many days to thanksgivnig from cpptipday?*/);
30 | static_assert(25d / November/ 2022 == /*when will be thankgiving next year?*/);
31 | ```
32 |
33 | > https://godbolt.org/z/6h755jqPE
34 |
35 |
Solutions
36 |
37 | ```cpp
38 | static_assert(thanksgiving.ok() /*is thanksgiving a valid date?*/);
39 | static_assert(Thursday == weekday{sys_days{thanksgiving}} /*what day is thanksgiving?*/);
40 | static_assert(days(4) == sys_days{thanksgiving} - sys_days{cpptipday} /*how many days to thanksgiving from cpptipday?*/);
41 | static_assert(24d / November/ 2022 == sys_days{Thursday[4] / November / 2022} /*when will be thanksgiving next year?*/);
42 | ```
43 |
44 | > https://jonathan.godbolt.org/z/G6T4zEKn1
45 |
46 | ```cpp
47 | static_assert(thanksgiving.ok());
48 | static_assert(Thursday == weekday{sys_days(thanksgiving)});
49 | static_assert(days(4) == thanksgiving.day() - cpptipday.day());
50 | static_assert(25d / November/ 2022 == thanksgiving + years(1));
51 | ```
52 |
53 | > https://godbolt.org/z/e37KPxGbv
54 |
55 |
56 | ```cpp
57 | static_assert(thanksgiving.ok() /*is thanksgivng a valid date?*/);
58 | static_assert(Thursday == weekday{thanksgiving} /*what day is thanksgiving?*/);
59 | static_assert(days(4) == thanksgiving.day() - cpptipday.day() /*how many days to thanksgiving from cpptipday?*/);
60 | static_assert(24d / November/ 2022 == sys_days{2022y / November/ Thursday[4]} /*when will be thankgiving next year?*/);
61 | ```
62 |
63 | > https://godbolt.org/z/qKcE4x373
64 |
--------------------------------------------------------------------------------
/tips/258.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that static reflection can be used to invoke functions with named parameters?**
4 |
5 | * https://wg21.link/P0385
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct foo {
11 | auto api(int i) -> void { std::cout << i; }
12 | };
13 |
14 | auto main() -> int {
15 | namespace meta = std::experimental::reflect;
16 | foo f{};
17 | (f.*meta::get_pointer_v>>)(42); // prints 42
18 | }
19 | ```
20 |
21 | > https://godbolt.org/z/sMeeo981v
22 |
23 |
Puzzle
24 |
25 | * **Can you implement invoke which calls given by name function from reflected struct with given named parameters?**
26 |
27 | ```cpp
28 | template /*TODO*/ invoke{};
29 |
30 | struct foo {
31 | auto bar(int value) { bar_called_with = value; }
32 | auto baz(int i, double d) { baz_called_with = {i, d}; }
33 |
34 | std::optional bar_called_with{};
35 | std::optional> baz_called_with{};
36 | };
37 |
38 | int main() {
39 | using namespace boost::ut;
40 |
41 | "invoke"_test = [] {
42 | should("support single value") = [] {
43 | foo f{};
44 | invoke<"bar">(f, "value"_arg = 42);
45 | expect(not f.baz_called_with and f.bar_called_with and *f.bar_called_with == 42_i);
46 | };
47 |
48 | should("support diff order") = [] {
49 | foo f{};
50 | invoke<"baz">(f, "i"_arg = 4, "d"_arg = 2.0);
51 | expect(not f.bar_called_with and f.baz_called_with and *f.baz_called_with == std::pair{4, 2.});
52 | };
53 |
54 | should("support diff order") = [] {
55 | foo f{};
56 | invoke<"baz">(f, "d"_arg = 0., "i"_arg = 42);
57 | expect(not f.bar_called_with and f.baz_called_with and *f.baz_called_with == std::pair{42, .0});
58 | };
59 | };
60 | }
61 | ```
62 |
63 | > https://godbolt.org/z/zTnEeaTxf
64 |
65 |
Solutions
66 |
67 | ```cpp
68 | template decltype(auto) invoke(T& t, Args&&...args) {
69 | const auto get_arg = [&] {
70 | return ([&] -> meta::get_reflected_type_t> {
71 | if constexpr(std::string_view{meta::get_name_v} == Args::name) {
72 | return args.value;
73 | } else {
74 | return {};
75 | }}() + ...); // exploiting +
76 | };
77 |
78 | const auto call = [&] -> bool {
79 | if constexpr (std::string_view{meta::get_name_v} == Name) {
80 | const auto f = meta::get_pointer_v;
81 | using params_t = meta::get_parameters_t;
82 | [&] (TParams, std::index_sequence) {
83 | (t.*f)(get_arg.template operator()>()...);
84 | }(params_t{}, std::make_index_sequence>{});
85 | return true;
86 | } else {
87 | return false;
88 | }
89 | };
90 |
91 | using type = meta::get_aliased_t;
92 | using member_functions_t = meta::get_member_functions_t;
93 | std::apply([&] (Fs...) {
94 | (call.template operator()() or ...);
95 | }, meta::unpack_sequence_t{});
96 | }
97 | ```
98 |
99 | > https://godbolt.org/z/Ka3xYYd7a
100 |
--------------------------------------------------------------------------------
/tips/260.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added std::move_only_function?**
4 |
5 | * https://wg21.link/P0288
6 |
7 |
Example
8 |
9 | ```cpp
10 | #include
11 |
12 | int main() {
13 | {
14 | std::function f{[]{return 42; }};
15 | auto copy = f; // okay
16 | auto value = f();
17 | }
18 |
19 | {
20 | std::move_only_function f{[] {return 42; }};
21 | auto copy = f; // error, call to deleted copy constructor
22 | auto value = f(); // undefined behaviour, dandling reference
23 | }
24 | }
25 | ```
26 |
27 | > https://godbolt.org/z/KWTx4nd3n
28 |
29 |
Puzzle
30 |
31 | * **Can you comment out and fill `???` with appropirate function type (std::function or std::move_only_function) when applicable?**
32 |
33 | ```cpp
34 | int main() {
35 | {
36 | auto f = [] { return 42; };
37 | // TODO
38 | // ??? f1 = f;
39 | // ??? f2 = std::move(f);
40 | }
41 |
42 | {
43 | auto value = 42;
44 | auto f = [v = std::move(value)] { return v; };
45 | // TODO
46 | // ??? f1 = f;
47 | // ??? f2 = std::move(f);
48 | }
49 |
50 | {
51 | auto f = [u = std::make_unique(42)] { return *u; };
52 | // TODO
53 | // ??? f1 = f;
54 | // ??? f2 = std::move(f);
55 | }
56 | }
57 | ```
58 |
59 | > https://godbolt.org/z/hK4EGvd1q
60 |
61 |
Solutions
62 |
--------------------------------------------------------------------------------
/tips/261.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added Monadic operations for std::optional?**
4 |
5 | * https://wg21.link/P0798
6 |
7 |
Example
8 |
9 | ```cpp
10 | int main() {
11 | auto opt = std::optional{42};
12 | opt.and_then([](auto o)->std::optional{ std::cout << o;; return std::nullopt; });// prints 42
13 | }
14 | ```
15 |
16 | > https://godbolt.org/z/aeKWEa63b
17 |
18 |
Puzzle
19 |
20 | * **Can you refactor `execute` routine with monadic Monadic operations?**
21 |
22 | ```cpp
23 | struct market_data{};
24 | struct trade{};
25 | struct order{};
26 | struct order_with_id{};
27 |
28 | std::optional execute(auto& ts, const market_data& md) {
29 | auto trade = ts.parse(md);
30 | if (not trade) {
31 | return std::nullopt;
32 | }
33 |
34 | auto order = ts.model(*trade);
35 | if (not order) {
36 | return std::nullopt;
37 | }
38 |
39 | if (auto order_with_id = ts.map(*order)) {
40 | return order_with_id;
41 | } else {
42 | return std::nullopt;
43 | }
44 | }
45 |
46 | int main(){
47 | using namespace boost::ut;
48 |
49 | should("produce bail out on market data") = [] {
50 | struct {
51 | auto parse(const market_data&) -> std::optional { return {}; }
52 | auto model(const trade&) -> std::optional { return {{}}; }
53 | auto map(const order&) -> std::optional { return {{}}; }
54 | } fake_ts;
55 |
56 | expect(not execute(fake_ts, {}).has_value());
57 | };
58 |
59 | should("produce bail out on model") = [] {
60 | struct {
61 | auto parse(const market_data&) -> std::optional { return {{}}; }
62 | auto model(const trade&) -> std::optional { return {}; }
63 | auto map(const order&) -> std::optional { return {{}}; }
64 | } fake_ts;
65 |
66 | expect(not execute(fake_ts, {}).has_value());
67 | };
68 |
69 | should("produce bail out on map") = [] {
70 | struct {
71 | auto parse(const market_data&) -> std::optional { return {{}}; }
72 | auto model(const trade&) -> std::optional { return {{}}; }
73 | auto map(const order&) -> std::optional { return {}; }
74 | } fake_ts;
75 |
76 | expect(not execute(fake_ts, {}).has_value());
77 | };
78 |
79 | should("produce an order") = [] {
80 | struct {
81 | auto parse(const market_data&) -> std::optional { return {{}}; }
82 | auto model(const trade&) -> std::optional { return {{}}; }
83 | auto map(const order&) -> std::optional { return {{}}; }
84 | } fake_ts;
85 |
86 | expect(execute(fake_ts, {}).has_value());
87 | };
88 | }
89 | ```
90 |
91 | > https://godbolt.org/z/oG4qMPxEe
92 |
93 |
Solutions
94 |
95 | ```cpp
96 | std::optional execute(auto& ts, const market_data& md) {
97 | return ts.parse(md)
98 | .and_then([&](const trade& t) { return ts.model(t); })
99 | .and_then([&](const order& o) { return ts.map(o); });
100 | }
101 | ```
102 |
103 | > https://godbolt.org/z/z36z3f9cd
104 |
105 | ```cpp
106 | std::optional execute(auto& ts, const market_data& md) {
107 | auto model = [&ts](const auto &t){ return ts.model(t); };
108 | auto map = [&ts](const auto &o){ return ts.map(o); };
109 |
110 | return ts.parse(md)
111 | .and_then(model)
112 | .and_then(map);
113 | }
114 | ```
115 |
116 | > https://godbolt.org/z/se6MYh11q
117 |
118 | ```cpp
119 | decltype(auto) operator|(auto&& x, auto&& p) { return x.and_then(p); }
120 |
121 | std::optional execute(auto& ts, const market_data& md) {
122 | return ts.parse(md) | [&ts](auto o) { return ts.model(o); } |
123 | [&ts](auto o) { return ts.map(o); };
124 | }
125 | ```
126 |
127 | > https://godbolt.org/z/GEf5j6zej
128 |
--------------------------------------------------------------------------------
/tips/264.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++20 added `__VA_OPT__` for comma omission and comma deletion?**
4 |
5 | * https://wg21.link/P0306
6 |
7 |
Example
8 |
9 | ```cpp
10 | #define VARIADIC(...) __VA_OPT__(__LINE__)
11 |
12 | VARIADIC() // `empty`
13 | VARIADIC(a) // `line` 4
14 | VARIADIC(a, b) // `line` 5
15 | ```
16 |
17 | > https://godbolt.org/z/rsj9ax7xY
18 |
19 |
Puzzle
20 |
21 | * **Can you implement LOG1/LOG2 macros which will return formatted string and will apply `__VA_OPT__`?**
22 |
23 | ```cpp
24 | #define LOG1($fmt, ...) // TODO
25 | #define LOG2(...) // TODO
26 |
27 | int main() {
28 | using namespace boost::ut;
29 | using std::string_literals::operator""s;
30 |
31 | expect(""s == LOG1(""));
32 | expect("42"s == LOG1("42"));
33 | expect("4"s == LOG1("%d", 4));
34 |
35 | expect(""s == LOG2(""));
36 | expect("42"s == LOG2("42"));
37 | expect("4"s == LOG2("%d", 4));
38 | }
39 | ```
40 |
41 | > https://godbolt.org/z/sPTqoEdMG
42 |
43 |
Solutions
44 |
45 | ```cpp
46 | #define LOG1($fmt, ...) fmt::sprintf($fmt __VA_OPT__(,) __VA_ARGS__)
47 | #define LOG2(...) __VA_OPT__(fmt::sprintf(__VA_ARGS__))
48 | ```
49 |
50 | > https://godbolt.org/z/5TM7WsMfx
51 |
52 | ```cpp
53 | #define LOG1($fmt, ...) fmt::sprintf($fmt __VA_OPT__(,) __VA_ARGS__)
54 | #define LOG2(...) fmt::sprintf(__VA_ARGS__)
55 | ```
56 |
57 | > https://godbolt.org/z/135j8s5PP
58 |
--------------------------------------------------------------------------------
/tips/265.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added Attributes on Lambda-Expressions?**
4 |
5 | * https://wg21.link/P2173
6 |
7 |
Example
8 |
9 | ```cpp
10 | constexpr auto foo = [] [[deprecated]] { };
11 |
12 | int main() {
13 | foo(); // operator() is deprecated
14 | }
15 | ```
16 |
17 | > https://godbolt.org/z/MaeTnG9eb
18 |
19 |
Puzzle
20 |
21 | * **Can you implement variable template lambda expression `foo` which is marked nodiscard for integral types?**
22 |
23 | ```cpp
24 | //TODO foo
25 |
26 | int main() {
27 | using namespace boost::ut;
28 |
29 | "should be callable for non integral types"_test = [] {
30 | foo();
31 | foo();
32 | };
33 |
34 | "should verify the result for integral types"_test = [] {
35 | expect(0_c == foo());
36 | expect(not foo());
37 | expect(0_s == foo());
38 | expect(0_i == foo());
39 | };
40 |
41 | "should ignore the result for integral types"_test = [] {
42 | /*TODO*/ foo();
43 | /*TODO*/ foo();
44 | /*TODO*/ foo();
45 | /*TODO*/ foo();
46 | };
47 | }
48 | ```
49 |
50 | > https://godbolt.org/z/fKfjsbWoh
51 |
52 |
Solutions
53 |
--------------------------------------------------------------------------------
/tips/266.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know wrapping an unqualified function name in parentheses suppresses argument-dependent lookup?**
4 |
5 | * http://eel.is/c++draft/basic.lookup#basic.lookup.argdep-1
6 |
7 |
Example
8 |
9 | ```cpp
10 | namespace adl {
11 | struct foo {};
12 | void bar(foo) {}
13 | }
14 |
15 | int main() {
16 | adl::foo foo;
17 | bar(foo); // OK, ADL
18 | (bar)(foo); // error: no ADL
19 | }
20 | ```
21 |
22 | > https://godbolt.org/z/ba7Pvqa75
23 |
24 |
Puzzle
25 |
26 | * **Can you implement function bar which returns { 0: if it's not ADL call, 42: if it's a qualified call; ambigious error: if it's an ADL call }?**
27 |
28 | ```cpp
29 | #include
30 |
31 | //TODO
32 |
33 | int main() {
34 | static_assert([](auto foo) { return requires { adl::bar(foo); }; }(adl::foo{}));
35 | assert(42 == adl::bar(adl::foo{}));
36 |
37 | static_assert([](auto foo) { return requires { ::bar(foo); }; }(adl::foo{}));
38 | assert(0 == ::bar(adl::foo{}));
39 |
40 | static_assert([](auto foo) { return requires { (bar)(foo); }; }(adl::foo{}));
41 | assert(0 == (bar)(adl::foo{}));
42 |
43 | static_assert(not [](auto foo) { return requires { bar(foo); }; }(adl::foo{}));
44 | }
45 | ```
46 |
47 | > https://godbolt.org/z/cxhxW9n8Y
48 |
49 |
Solutions
50 |
51 | ```cpp
52 | namespace adl {
53 | struct foo {};
54 | constexpr auto bar(foo) -> int { return 42; }
55 | }
56 |
57 | constexpr auto bar(adl::foo) -> int { return 0; }
58 | ```
59 |
60 | > https://godbolt.org/z/MPTfK7sKq
61 |
62 | ```cpp
63 | namespace adl {
64 |
65 | struct foo {};
66 | [[nodiscard]] constexpr auto bar(const foo) noexcept -> int { return 42; }
67 |
68 | } // namespace adl
69 |
70 | [[nodiscard]] constexpr auto bar(const adl::foo) noexcept -> int { return 0; }
71 | ```
72 |
73 | > https://godbolt.org/z/73YbYorj3
74 |
--------------------------------------------------------------------------------
/tips/277.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++17 structured bindings support to custom classes can be added?**
4 |
5 | * https://wg21.link/P1061
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct foo {
11 | int i{};
12 | std::string s{};
13 | };
14 |
15 | template
16 | const auto& get(const foo& f) {
17 | if constexpr (N == 0) {
18 | return f.i;
19 | } else if constexpr (N == 1) {
20 | return f.s;
21 | }
22 | }
23 |
24 | namespace std {
25 | template <>
26 | struct tuple_size<::foo> : integral_constant {};
27 |
28 | template
29 | struct tuple_element {
30 | using type = decltype(get(std::declval<::foo&>()));
31 | };
32 | } // namespace std
33 |
34 | int main() {
35 | auto [i, s] = foo{.i = 42, .s = "str"};
36 | assert(42 == i);
37 | assert("str" == s);
38 | }
39 | ```
40 |
41 | > https://godbolt.org/z/n66GMfWao
42 |
43 |
Puzzle
44 |
45 | * **Can you add structured bindings support to std::index_sequence?**
46 |
47 | ```cpp
48 | namespace std {
49 | // TODO
50 | }
51 |
52 | int main() {
53 | {
54 | auto [... Is] = std::make_index_sequence<0>{};
55 | static_assert(sizeof...(Is) == 0);
56 | }
57 | {
58 | auto [... Is] = std::make_index_sequence<3>{};
59 | static_assert(sizeof...(Is) == 3);
60 | static_assert(
61 | typeid(std::tuple{std::integral_constant{},
62 | std::integral_constant{},
63 | std::integral_constant{}}) ==
64 | typeid(std::tuple{Is...}));
65 | }
66 | {
67 | auto [... Is] = std::make_index_sequence<42>{};
68 | static_assert(sizeof...(Is) == 42);
69 | }
70 | }
71 | ```
72 |
73 | > https://godbolt.org/z/qavcThr9K
74 |
75 |
Solutions
76 |
77 | ```cpp
78 | namespace std {
79 |
80 | template
81 | using index_constant = std::integral_constant;
82 |
83 | template
84 | auto get(index_sequence) {
85 | return index_constant{};
86 | }
87 |
88 | template
89 | struct tuple_size> : index_constant {};
90 |
91 | template
92 | struct tuple_element> {
93 | using type = index_constant;
94 | };
95 |
96 | } // namespace std
97 | ```
98 |
99 | > https://godbolt.org/z/466j7snqK
100 |
101 | ```cpp
102 | namespace std {
103 |
104 | template
105 | auto constexpr get(const index_sequence&) {
106 | return get(tuple{integral_constant{}...});
107 | };
108 |
109 | template
110 | struct tuple_size> : integral_constant {};
111 |
112 | template
113 | struct tuple_element> {
114 | using type = decltype(get(tuple{integral_constant{}...}));
115 | };
116 | }
117 | ```
118 |
119 | > https://godbolt.org/z/6fb7e89fK
120 |
121 | ```cpp
122 | namespace stdext {
123 |
124 | template
125 | struct index_sequence : std::index_sequence {
126 | template
127 | auto get() const -> std::tuple_element_t {
128 | return {};
129 | }
130 | };
131 |
132 | namespace detail {
133 |
134 | template >
135 | struct make_index_sequence;
136 |
137 | template
138 | struct make_index_sequence> {
139 | using type = index_sequence;
140 | };
141 |
142 | } // namespace detail
143 |
144 | template
145 | using make_index_sequence = typename detail::make_index_sequence::type;
146 |
147 | } // namespace stdext
148 | ```
149 |
150 | > https://godbolt.org/z/jeY9qoYG4
151 |
--------------------------------------------------------------------------------
/tips/278.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added Literal Suffix for (signed) size_t?**
4 |
5 | * https://wg21.link/p0330
6 |
7 |
Example
8 |
9 | ```cpp
10 | static_assert(-42 == -42z);
11 | static_assert(-42 == -42Z);
12 | static_assert(42 == 42uz);
13 | static_assert(42 == 42uZ);
14 | static_assert(42 == 42Uz);
15 | static_assert(42 == 42ZU);
16 | static_assert(42 == 42Zu);
17 |
18 | static_assert(std::is_same_v);
19 | ```
20 |
21 | > https://godbolt.org/z/Wxe9Kfze3
22 |
23 |
Puzzle
24 |
25 | * **Can you make the following snippets compatible with 32/64 bit arch?**
26 |
27 | ```cpp
28 | int main() {
29 | std::vector v{1, 2, 3};
30 |
31 | for (auto i = 0; i < v.size(); ++i) {
32 | }
33 |
34 | for (auto i = 0, s = std::size(v); i < s; ++i) {
35 | }
36 |
37 | std::max(0, std::ssize(v));
38 | std::min(0, std::size(v));
39 | std::max(0, std::min(0, v.size()));
40 | }
41 | ```
42 |
43 | > https://godbolt.org/z/EEdfz5451
44 |
45 |
Solutions
46 |
47 | ```cpp
48 | for (auto i = 0uz; i < v.size(); ++i) {
49 | }
50 |
51 | for (auto i = 0uz, s = std::size(v); i < s; ++i) {
52 | }
53 |
54 | std::max(0z, std::ssize(v));
55 | std::min(0uz, std::size(v));
56 | std::max(0uz, std::min(0uz, v.size()));
57 | ```
58 |
59 | > https://godbolt.org/z/dfTbhx1r7
60 |
61 | ```cpp
62 | #include // Change vector to array for elision of generated code. :)
63 |
64 | int main() {
65 | std::array v{1, 2, 3};
66 |
67 | for (auto i = 0uz; i < v.size(); ++i) {
68 | }
69 |
70 | for (auto i = 0uz, s = std::size(v); i < s; ++i) {
71 | }
72 |
73 | std::max(0z, std::ssize(v));
74 | std::min(0uz, std::size(v));
75 | std::max(0uz, std::min(0uz, v.size()));
76 | }
77 | ```
78 |
79 | > https://godbolt.org/z/GhdW1Ebo8
80 |
81 | ```cpp
82 | int main() {
83 | std::vector v{1, 2, 3};
84 |
85 | for (auto i = 0uz; i < v.size(); ++i) {
86 | }
87 |
88 | for (auto i = 0uz, s = std::size(v); i < s; ++i) {
89 | }
90 |
91 | std::max(0z, std::ssize(v));
92 | std::min(0uz, std::size(v));
93 | std::max(0uz, std::min(0uz, v.size()));
94 | }
95 | ```
96 |
97 | > https://godbolt.org/z/KeKKPG7cv
98 |
99 | ```cpp
100 | int main() {
101 | std::vector v{1, 2, 3};
102 |
103 | for (auto i = 0UZ; i < v.size(); ++i) {
104 | }
105 |
106 | for (auto i = 0UZ, s = std::size(v); i < s; ++i) {
107 | }
108 |
109 | std::max(0Z, std::ssize(v));
110 | std::min(0UZ, std::size(v));
111 | std::max(0UZ, std::min(0UZ, v.size()));
112 | }
113 | ```
114 |
115 | > https://godbolt.org/z/xxqzE1cee
116 |
--------------------------------------------------------------------------------
/tips/279.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * Did you know that C++20 made `std::string` constexpr?
4 |
5 | * https://wg21.link/P0980R1
6 |
7 |
Example
8 |
9 | ```cpp
10 | #include
11 |
12 | constexpr auto foo() {
13 | return std::string{"bar"};
14 | }
15 |
16 | static_assert("bar" == foo());
17 | ```
18 |
19 | > https://godbolt.org/z/P9qW6jYav
20 |
21 |
Puzzle
22 |
23 | * **Can you implement `concat` which concatenates given strings?**
24 |
25 | ```cpp
26 | [[nodiscard]] constexpr auto concat(auto... args); // TODO
27 |
28 | static_assert(""s == concat());
29 | static_assert("a"s == concat([]{return "a"s;}));
30 | static_assert("ab"s == concat([]{return "a"s;}, []{return "b"s;}));
31 | static_assert("abc"s == concat([]{return "a"s;}, []{return "b"s;}, []{return "c"s;}));
32 | ```
33 |
34 | > https://godbolt.org/z/6MaMqrKzE
35 |
36 |
Solutions
37 |
38 | ```cpp
39 | [[nodiscard]] constexpr auto concat(auto... args) {
40 | return ( ""s + ... + args() );
41 | }
42 | ```
43 |
44 | > https://cpp_tip_of_the_week.godbolt.org/z/3f7fh4Yd5
45 |
46 | ```cpp
47 | [[nodiscard]] constexpr auto concat(auto... args) {
48 | std::string result{};
49 | (result.append(args()), ...);
50 | return result;
51 | }
52 | ```
53 |
54 | > https://godbolt.org/z/xh8oancaf
55 |
56 | ```cpp
57 | [[nodiscard]] constexpr auto concat(auto... args) {
58 | return (args() + ... + std::string{});
59 | }
60 | ```
61 |
62 | > https://godbolt.org/z/rjPz7qnn8
63 |
64 | ```cpp
65 | [[nodiscard]] constexpr auto concat(auto... args){
66 | if constexpr(sizeof...(args) > 0){
67 | return std::string{(args() + ...)};
68 | }
69 | return std::string{};
70 | }
71 | ```
72 |
73 | > https://godbolt.org/z/c4eojWhTs
74 |
75 | ```cpp
76 | [[nodiscard]] constexpr auto concat(auto... args) {
77 | return (args() + ... + ""s);
78 | }
79 | ```
80 |
81 | > https://godbolt.org/z/TeEcEWcra
82 |
--------------------------------------------------------------------------------
/tips/290.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that lambda expression is guaranteed to have a unique type?**
4 |
5 | * https://eel.is/c++draft/expr.prim.lambda
6 |
7 |
Example
8 |
9 | ```cpp
10 | static_assert(typeid([]{}) != typeid([]{}));
11 |
12 | template
13 | struct foo{};
14 |
15 | foo f1, f2;
16 | static_assert(typeid(f1) != typeid(f2));
17 | ```
18 |
19 | > https://godbolt.org/z/Wrhfqba69
20 |
21 |
Puzzle
22 |
23 | * **Can you implement `create` which creates given type as a unique type or same type?**
24 |
25 | * Note: For type uniqueness inheritance might be used
26 |
27 | ```cpp
28 | class same;
29 | class unique;
30 |
31 | template
32 | [[nodiscard]] constexpr auto create(); // TODO
33 |
34 | struct foo {};
35 | static_assert(typeid(create()) == typeid(create()));
36 | static_assert(typeid(create()) != typeid(create()));
37 | ```
38 |
39 | > https://godbolt.org/z/YKKej87dE
40 |
41 |
Solutions
42 |
43 | ```cpp
44 | template
45 | struct wrap_unique: T {};
46 |
47 | template
48 | [[nodiscard]] constexpr std::convertible_to auto create()
49 | {
50 | if constexpr (std::same_as) {
51 | return wrap_unique{};
52 | } else {
53 | return T{};
54 | }
55 | }
56 | ```
57 |
58 | > https://godbolt.org/z/j5xvPzd47
59 |
60 | ```cpp
61 | template
62 | struct uniquify : T {};
63 |
64 | template >
65 | [[nodiscard]] constexpr auto create()
66 | -> std::conditional_t, U, T>;
67 | ```
68 |
69 | > https://godbolt.org/z/s6o7E4Kj6
70 |
71 | ```cpp
72 | template
73 | struct uniquify : T {};
74 |
75 | template
76 | [[nodiscard]] constexpr auto create() {
77 | if constexpr (std::same_as) {
78 | return uniquify{};
79 | } else {
80 | return T{};
81 | }
82 | }
83 | ```
84 |
85 | > https://godbolt.org/z/K8q3KdGbx
86 |
87 | ```cpp
88 | template
89 | [[nodiscard]] constexpr auto create() {
90 | if constexpr (std::is_same_v) {
91 | return UniqueLambda;
92 | }
93 | }
94 | ```
95 |
96 | > https://godbolt.org/z/nTb5h5x4o
97 |
98 | ```cpp
99 | template
100 | [[nodiscard]] constexpr auto create() {
101 | if constexpr (std::is_same_v) {
102 | return first{};
103 | } else {
104 | return [] {};
105 | }
106 | }
107 | ```
108 |
109 | > https://godbolt.org/z/Msodn95Tf
110 |
111 | ```cpp
112 | template
113 | class Holder : Tp {};
114 |
115 | template >
116 | [[nodiscard]] constexpr auto create() {
117 | if constexpr (std::is_same_v)
118 | return Tp{};
119 | else
120 | return Held{};
121 | }
122 | ```
123 |
124 | > https://godbolt.org/z/r8jcWz5ee
125 |
126 | ```cpp
127 | template
128 | class diff : T{};
129 |
130 | template>
131 | [[nodiscard]] constexpr auto create(){
132 | if constexpr(std::is_same_v){
133 | return V{};
134 | }
135 | }
136 | ```
137 |
138 | > https://godbolt.org/z/47Wc8r5js
139 |
--------------------------------------------------------------------------------
/tips/293.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++17 [[nodiscard]] attribute can be applied not only to function?**
4 |
5 | * http://eel.is/c++draft/dcl.attr.nodiscard#:attribute,nodiscard
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct foo {
11 | [[nodiscard]] foo(auto& resource) {}
12 | };
13 |
14 | struct [[nodiscard]] bar {};
15 |
16 | auto fn() -> bar;
17 |
18 | [[nodiscard]] auto fn2() -> bool;
19 |
20 | int main(int, char** argv){
21 | foo{argv}; // ignoring temp created by [[nodiscard]]
22 | fn(); // ignoring return value with [[nodiscard]]
23 | fn2(); // ignoring return value with [[nodiscard]]
24 | }
25 | ```
26 |
27 | > https://godbolt.org/z/Mch6cGM1h
28 |
29 |
Puzzle
30 |
31 | * **Can you mark all provided types/functions as [[nodiscard]] and handle the consequenes?**
32 |
33 | * Do you know any production use cases when applying nodiscard for non-functions improves the code?
34 |
35 | ```cpp
36 | // TODO: mark nodiscard
37 | struct foo { };
38 | auto fn1() -> foo;
39 | auto fn2() -> bool;
40 |
41 | int main() {
42 | // TODO: handle nodiscard
43 | foo();
44 | fn1();
45 | fn2();
46 | }
47 | ```
48 |
49 | > https://godbolt.org/z/coPPe4KTP
50 |
51 |
Solutions
52 |
53 | ```cpp
54 | struct [[nodiscard]] foo { };
55 | [[nodiscard]] auto fn1() -> foo;
56 | [[nodiscard]] auto fn2() -> bool;
57 |
58 | int main() {
59 | (void)foo();
60 | (void)fn1();
61 | (void)fn2();
62 | }
63 | ```
64 |
65 | > https://godbolt.org/z/h997hnKM4
66 |
67 | ```cpp
68 | struct [[nodiscard]] foo { };
69 | [[nodiscard]] auto fn1() -> foo;
70 | [[nodiscard]] auto fn2() -> bool;
71 |
72 | int main() {
73 | std::ignore = foo();
74 | std::ignore = fn1();
75 | std::ignore = fn2();
76 | }
77 | ```
78 |
79 | > https://godbolt.org/z/MjjM8fdrn
80 |
81 | ```cpp
82 | struct [[nodiscard]] foo { };
83 | [[nodiscard]] auto fn1() -> foo;
84 | [[nodiscard]] auto fn2() -> bool;
85 |
86 | int main() {
87 | auto not_ignored = foo();
88 | auto not_ignored1 = fn1();
89 | auto not_ignored2 = fn2();
90 | }
91 | ```
92 |
93 | > https://godbolt.org/z/sf9qPfj48
94 |
95 | ```cpp
96 | struct [[nodiscard]] foo { };
97 | [[nodiscard]] auto fn1() -> foo;
98 | [[nodiscard]] auto fn2() -> bool;
99 |
100 | int main() {
101 | [[maybe_unused]] auto f = foo{};
102 | (void) fn1();
103 | ignore = fn2();
104 | }
105 | ```
106 |
107 | > https://godbolt.org/z/eja8rc4sf
108 |
109 | ```cpp
110 | struct [[nodiscard]] foo {};
111 | auto fn1() -> foo;
112 | [[nodiscard]] auto fn2() -> bool;
113 |
114 | int main() {
115 | std::ignore = foo();
116 | std::ignore = fn1();
117 | std::ignore = fn2();
118 | }
119 | ```
120 |
121 | > https://godbolt.org/z/a73973Ge3
122 |
123 | ```cpp
124 | struct [[nodiscard]] foo { };
125 | [[nodiscard]] auto fn1() -> foo;
126 | [[nodiscard]] auto fn2() -> bool;
127 |
128 | int main() {
129 | static_cast(foo());
130 | [[maybe_unused]] foo Ω = fn1();
131 | std::ignore = fn2();
132 | }
133 | ```
134 |
135 | > https://godbolt.org/z/1WYx6WesG
136 |
137 | ```cpp
138 | struct [[nodiscard("Attribute 1")]] foo { };
139 | [[nodiscard("Attribute 2")]] auto fn1() -> foo;
140 | [[nodiscard("Attribute 3")]] auto fn2() -> bool;
141 |
142 | int main() {
143 | // TODO: handle nodiscard
144 | static_cast(foo());
145 | static_cast(fn1());
146 | auto or_this = fn2();
147 | }
148 | ```
149 |
150 | > https://godbolt.org/z/z5KTYG6s4
151 |
152 | ```cpp
153 | struct [[nodiscard]] foo {};
154 | auto fn1() -> foo;
155 | [[nodiscard]] auto fn2() -> bool;
156 |
157 | int main() {
158 | // TODO: handle nodiscard
159 | static_cast(foo());
160 | static_cast(fn1());
161 | static_cast(fn2());
162 | }
163 | ```
164 |
165 | > https://godbolt.org/z/4c8rhq3W7
166 |
--------------------------------------------------------------------------------
/tips/298.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++23 added static operator()?**
4 |
5 | * https://wg21.link/P1169
6 |
7 |
Example
8 |
9 | ```cpp
10 | struct s {
11 | static constexpr auto operator()() { return 1; }
12 | };
13 | auto l = [] static { return 2; };
14 |
15 | static_assert(3 == s{}() + l());
16 |
17 | static_assert(3 == s::operator()() +
18 | decltype(l)::operator()());
19 | ```
20 |
21 | > https://godbolt.org/z/43hhKcr59
22 |
23 |
Puzzle
24 |
25 | * **Can you implement count which returns number of types which can be called with static operator()?**
26 |
27 | ```cpp
28 | template
29 | constexpr auto count = 0; // TODO
30 |
31 | struct e {};
32 | struct s {
33 | static constexpr auto operator()() -> void;
34 | };
35 | struct ns {
36 | constexpr auto operator()() -> void;
37 | };
38 |
39 | auto l = [] { };
40 | auto sl = [] static {};
41 |
42 | static_assert(0 == count);
43 | static_assert(1 == count);
44 | static_assert(0 == count);
45 | static_assert(0 == count);
46 | static_assert(1 == count);
47 | static_assert(2 == count);
48 | ```
49 |
50 | > https://godbolt.org/z/McrMfasjq
51 |
52 |
Solutions
53 |
54 | ```c++
55 | template
56 | constexpr auto count = (requires { (void*)&Ts::operator(); } + ... + 0);
57 | ```
58 |
59 | > https://godbolt.org/z/Td6zxxaoM
60 |
61 | ```c++
62 | template
63 | constexpr auto count = (0 + ... + requires{Ts::operator();});
64 | ```
65 |
66 | > https://godbolt.org/z/P74br35qh
67 |
68 | ```cpp
69 | template
70 | constexpr auto count = (... + requires { Ts::operator()(); });
71 | ```
72 |
73 | > https://godbolt.org/z/KoP4sxrxr
74 |
75 | ```cpp
76 | template
77 | concept is_static_call_operator = requires{T::operator()();};
78 |
79 | template
80 | constexpr auto count = (0 + ... + is_static_call_operator)
81 | ```
82 |
83 | > https://godbolt.org/z/TEPKG3xa8
84 |
85 | ```cpp
86 | template
87 | constexpr auto count =
88 | (0 + ... + requires{Ts::operator()();})
89 | ```
90 |
91 | > https://godbolt.org/z/f1xKoEvKz
92 |
93 | ```cpp
94 | template
95 | constexpr auto has_static_operator = [](){
96 | if constexpr (requires { T::operator();}){
97 | return 1;
98 | }
99 | else{
100 | return 0;
101 | }
102 | }();
103 |
104 | template
105 | constexpr auto count = [](){
106 | return 0 + (... + has_static_operator);
107 | }();
108 | ```
109 |
110 | > https://godbolt.org/z/j3a6o78Wf
111 |
112 | ```cpp
113 | template
114 | concept HasStaticOp = requires(T) { T::operator(); };
115 |
116 | template
117 | constexpr auto count = (HasStaticOp + ...);
118 | ```
119 |
120 | > https://godbolt.org/z/Yz53ebYn9
121 |
122 | ```cpp
123 | template
124 | constexpr auto count = [] -> int {
125 | return (requires {Ts::operator()();}+...);
126 | }();
127 | ```
128 |
129 | > https://godbolt.org/z/ne73vMMPW
130 |
--------------------------------------------------------------------------------
/tips/299.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you know that C++20 concepts can be used to avoid implicit conversions?**
4 |
5 | * https://eel.is/c++draft/concept.same
6 |
7 |
Example
8 |
9 | ```cpp
10 | #include
11 |
12 | void foo(int i);
13 | void bar(std::same_as auto i);
14 |
15 |
16 | int main() {
17 | foo(42.0); // implicit conversion
18 | bar(42.0); // error: contraint not satisifed
19 | }
20 | ```
21 |
22 | > https://godbolt.org/z/v45nYdaT7
23 |
24 |
Puzzle
25 |
26 | * **Can you implement conversion safe `invoke[args...]`?**
27 |
28 | * Note: Doesn't allow implicit conversions neither for parameters nor for the return type
29 |
30 | ```cpp
31 | struct {
32 | template
33 | [[nodiscard]] constexpr auto operator[](...); // TODO
34 | } invoke;
35 |
36 | auto foo(int, double, float) -> void;
37 |
38 | constexpr auto can_invoke_with = [](R fn(Ts...), auto&&... args) {
39 | return requires { { invoke.template operator[](fn, std::forward(args)...) } -> std::same_as; };
40 | };
41 |
42 | static_assert( can_invoke_with(foo, int{}, double{}, float{}));
43 | static_assert(not can_invoke_with(foo, int{}, float{}, float{}));
44 | static_assert(not can_invoke_with(foo, float{}, float{}, float{}));
45 | static_assert(not can_invoke_with(foo, short{}, int{}, double{}, float{}));
46 | static_assert(not can_invoke_with(foo, int{}, double{}, float{}, float{}));
47 | ```
48 |
49 | > https://godbolt.org/z/vz9sxssE4
50 |
51 |
Solutions
52 |
53 | ```cpp
54 | template
55 | [[nodiscard]] constexpr auto operator[](R fn(Ts...), std::same_as auto... ts ) -> R;
56 | ```
57 |
58 | > https://godbolt.org/z/T4rvx87Wo
59 |
60 | ```cpp
61 | template && ...), int> = 0>
64 | [[nodiscard]] constexpr auto operator[](R fn(Ts...), Ts2... ts ) -> R;
65 | ```
66 | > https://godbolt.org/z/7fecsaErf
67 |
68 | ```cpp
69 | struct {
70 | template
71 | [[nodiscard]] constexpr auto operator[](R fn(Ts...),
72 | std::same_as auto&&... args)
73 | -> std::same_as decltype(auto) {
74 | return fn(std::forward(args)...);
75 | }
76 | } invoke;
77 | ```
78 |
79 | > https://godbolt.org/z/cbGrTW74q
80 |
81 | ```cpp
82 | struct {
83 | template
84 | [[nodiscard]] constexpr auto operator[](R fn(Ts...), std::same_as auto&&... args){
85 | return fn(std::forward(args)...);
86 | }
87 | } invoke;
88 | ```
89 |
90 | > https://godbolt.org/z/53jaMTK6z
91 |
92 | ```cpp
93 | struct {
94 | template
95 | [[nodiscard]] constexpr auto operator[](auto&& fn, std::same_as auto&&... args) -> std::same_as auto {
96 | return fn(std::forward(args)...);
97 | }
98 | } invoke;
99 | ```
100 |
101 | > https://godbolt.org/z/Gjv51ev13
102 |
103 | ```cpp
104 | struct {
105 | template
106 | [[nodiscard]] constexpr auto operator[](auto fn, std::same_asauto ...params) -> std::same_as auto {
107 | return fn(params...);
108 | };
109 | } invoke;
110 | ```
111 |
112 | > https://godbolt.org/z/9vMh8sje6
113 |
114 | ```cpp
115 | struct {
116 | template
117 | [[nodiscard]] constexpr auto operator[](auto F, auto... args) -> std::same_as auto requires (std::same_as && ...) {
118 | return F(args...);
119 | };
120 | } invoke;
121 | ```
122 |
123 | > https://godbolt.org/z/TjbzWd7dT
124 |
125 | ```cpp
126 |
127 | struct {
128 | template
129 | [[nodiscard]] constexpr auto operator[](R fn(Ts...), std::same_as auto&& ... args)->R;
130 | } invoke;
131 | ```
132 |
133 | > https://godbolt.org/z/bz38Yb3c6
134 |
135 | ```cpp
136 | struct {
137 | template
138 | [[nodiscard]] constexpr auto operator[](auto f, std::same_as auto &&...args){
139 | f(args...);
140 | }
141 | } invoke;
142 | ```
143 |
144 | > https://godbolt.org/z/MP9nK16xr
145 |
--------------------------------------------------------------------------------
/tips/302.md:
--------------------------------------------------------------------------------
1 | Info
2 |
3 | * **Did you now that with concepts you can override a type?**
4 |
5 | * https://eel.is/c++draft/temp.concept#def:concept
6 |
7 |
Example
8 |
9 | ```cpp
10 | template struct foo {
11 | static constexpr auto value = N;
12 | };
13 | static_assert(42 == foo<42>::value);
14 |
15 | template
16 | requires true // override -> more specialized
17 | struct foo {
18 | static constexpr auto value = 0;
19 | };
20 | static_assert(42 == foo<42>::value); // memoized
21 | static_assert(0 == foo<43>::value);
22 | ```
23 |
24 | > https://godbolt.org/z/hPcsKG4an
25 |
26 |
Puzzle
27 |
28 | * **Can you override std::shared_ptr to avoid thred-safe guards?**
29 |
30 | ```cpp
31 | #include
32 |
33 | // TODO override shared_ptr with std::__shared_ptr which is is not thread-safe
34 | // NOTE overriding STL is UB
35 | // Alternative - boost::local_shared_ptr
36 |
37 | #include
38 | static_assert(std::is_base_of_v, std::shared_ptr>);
39 | ```
40 |
41 | > https://godbolt.org/z/7axP5or3q
42 |
43 |
Solutions
44 |
45 | ```cpp
46 | namespace std {
47 | template requires ::std::is_same_v
48 | class shared_ptr : public __shared_ptr {};
49 | }
50 | ```
51 |
52 | > https://godbolt.org/z/Mhj1M7Yec
53 |
54 | ```cpp
55 | namespace std {
56 | template
57 | requires std::is_integral_v
58 | class shared_ptr : public __shared_ptr {};
59 | } // namespace std
60 | ```
61 |
62 | > https://godbolt.org/z/sa9a937of
63 |
64 | ```cpp
65 | namespace boost{
66 | template requires std::is_same_v
67 | struct shared_ptr : std::__shared_ptr {
68 | };
69 | }
70 |
71 | static_assert(std::is_base_of_v, boost::shared_ptr>);
72 | ```
73 |
74 | > https://godbolt.org/z/acWKbG4fG
75 |
76 | ```cpp
77 | namespace std{
78 | template requires is_same_v
79 | struct shared_ptr : std::__shared_ptr {
80 | };
81 | }
82 |
83 | static_assert(std::is_base_of_v, std::shared_ptr