diff options
author | johannst <johannst@users.noreply.github.com> | 2024-02-15 23:29:57 +0000 |
---|---|---|
committer | johannst <johannst@users.noreply.github.com> | 2024-02-15 23:29:57 +0000 |
commit | bac8a5d2822835cf47175d1162030653fadd5c09 (patch) | |
tree | 28f312a114cf95ac799daac2a2caec4b8612d84d /development/c++.html | |
parent | bfc5ce4bc01e5eb28969eefcc01ecfefa2601fdf (diff) | |
download | notes-bac8a5d2822835cf47175d1162030653fadd5c09.tar.gz notes-bac8a5d2822835cf47175d1162030653fadd5c09.zip |
deploy: 4485708c972815bbb6df7f5a228683aa855d553d
Diffstat (limited to 'development/c++.html')
-rw-r--r-- | development/c++.html | 82 |
1 files changed, 41 insertions, 41 deletions
diff --git a/development/c++.html b/development/c++.html index c33016b..0d95860 100644 --- a/development/c++.html +++ b/development/c++.html @@ -326,7 +326,7 @@ int* P = reinterpret_cast<int*>(C); // Cast is ok, not yet UB. </li> <li> <p>On <code>gcc</code> strict aliasing is enabled starting with <code>-O2</code>.</p> -<pre><code class="language-bash">for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done +<pre><code class="language-bash">for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done -O0 -fstrict-aliasing [disabled] -O1 -fstrict-aliasing [disabled] -O2 -fstrict-aliasing [enabled] @@ -379,13 +379,13 @@ to violate self defined contract, see <a href="https://godbolt.org/z/e8x1af3Mh"> // Base case with one parameter. template<int P> void show_int() { - printf("%d\n", P); + printf("%d\n", P); } // General case with at least two parameters, to disambiguate from base case. template<int P0, int P1, int... Params> void show_int() { - printf("%d, ", P0); + printf("%d, ", P0); show_int<P1, Params...>(); } @@ -400,13 +400,13 @@ void show(const T& t) { // General case with at least two parameters, to disambiguate from base case. template<typename T0, typename T1, typename... Types> void show(const T0& t0, const T1& t1, const Types&... types) { - std::cout << t0 << ", "; + std::cout << t0 << ", "; show(t1, types...); } int main() { show_int<1, 2, 3, 4, 5>(); - show(1, 1.0, "foo", 'a'); + show(1, 1.0, "foo", 'a'); } </code></pre> <h2 id="forwarding-reference-fwd-ref"><a class="header" href="#forwarding-reference-fwd-ref">Forwarding reference (<a href="https://en.cppreference.com/w/cpp/language/reference#Forwarding_references">fwd ref</a>)</a></h2> @@ -456,21 +456,21 @@ void fwd_wrapper(T&& param) { // forwarding reference int main() { { - std::puts("==> wrapper rvalue reference"); + std::puts("==> wrapper rvalue reference"); wrapper(M{}); // calls use(M&). - std::puts("==> wrapper lvalue reference"); + std::puts("==> wrapper lvalue reference"); struct M m; wrapper(m); // calls use(M&). } { - std::puts("==> fwd_wrapper rvalue reference"); + std::puts("==> fwd_wrapper rvalue reference"); fwd_wrapper(M{}); // calls use(M&&). - std::puts("==> fwd_wrapper lvalue reference"); + std::puts("==> fwd_wrapper lvalue reference"); struct M m; fwd_wrapper(m); // calls use(M&). @@ -496,8 +496,8 @@ struct any_of<T, U0, U...> : any_of<T, U...> {}; template<typename T, typename... U> constexpr bool any_of_v = any_of<T, U...>::value; -static_assert(any_of_v<int, char, bool, int>, ""); -static_assert(!any_of_v<int, char, bool, float>, ""); +static_assert(any_of_v<int, char, bool, int>, ""); +static_assert(!any_of_v<int, char, bool, float>, ""); </code></pre> <h2 id="example-sfinae-enable_if"><a class="header" href="#example-sfinae-enable_if">Example: <a href="https://en.cppreference.com/w/cpp/language/sfinae">SFINAE</a> (<a href="https://en.cppreference.com/w/cpp/types/enable_if">enable_if</a>)</a></h2> <p>Provide a single entry point <code>Invoke</code> to call some <code>Operations</code>. @@ -543,16 +543,16 @@ namespace impl { template<typename Ctx, template<typename> class Op, typename... P, enable_if_bool<has_dst<Op<Ctx>>> = true> void Invoke(const Ctx& C, P... params) { - std::cout << "Invoke " << Op<Ctx>::Name << '\n'; + std::cout << "Invoke " << Op<Ctx>::Name << '\n'; typename Op<Ctx>::Return R = impl::Invoke<Ctx, Op>(C, params...); - std::cout << "returned -> " << R << '\n'; + std::cout << "returned -> " << R << '\n'; } // Invoke an OPERATION which has *NOT* a DESTINATION with arbitrary number of arguments. template<typename Ctx, template<typename> class Op, typename... P, disable_if_bool<has_dst<Op<Ctx>>> = true> void Invoke(const Ctx& C, P... params) { - std::cout << "Invoke " << Op<Ctx>::Name << " without destination." << '\n'; + std::cout << "Invoke " << Op<Ctx>::Name << " without destination." << '\n'; impl::Invoke<Ctx, Op>(C, params...); } @@ -560,7 +560,7 @@ void Invoke(const Ctx& C, P... params) { struct Ctx { void out(const char* s, unsigned v) const { - printf("%s%x\n", s, v); + printf("%s%x\n", s, v); } }; @@ -570,7 +570,7 @@ template<typename Ctx> struct OpA { using HasCtx = std::false_type; using Return = int; - static constexpr const char* const Name = "OpA"; + static constexpr const char* const Name = "OpA"; constexpr Return operator()(int a, int b) const { return a + b; @@ -581,10 +581,10 @@ template<typename Ctx> struct OpB { using HasCtx = std::true_type; using Return = void; - static constexpr const char* const Name = "OpB"; + static constexpr const char* const Name = "OpB"; Return operator()(const Ctx& C, unsigned a) const { - C.out("a = ", a); + C.out("a = ", a); } }; @@ -650,7 +650,7 @@ struct registry { const auto it = m_fns.find(nm); if (it == m_fns.end()) { static_assert(std::is_default_constructible_v<RET>, - "RET must be default constructible"); + "RET must be default constructible"); return {}; } return std::invoke(it->second, p...); @@ -661,7 +661,7 @@ struct registry { static bool regfn_##REGISTRY##NAME() { \ const bool r = REGISTRY::get().add(#NAME, NAME); \ if (!r) { \ - std::puts("Failed to register test " #NAME ", same name already registered!"); \ + std::puts("Failed to register test " #NAME ", same name already registered!"); \ std::abort(); \ } \ return r; \ @@ -677,10 +677,10 @@ struct registry { using REG1 = registry<void>; TEST(REG1, test1) { - std::puts("REG1::test1"); + std::puts("REG1::test1"); } TEST(REG1, test2) { - std::puts("REG1::test2"); + std::puts("REG1::test2"); } // -- Usage 2 with convenience macro wrapper. @@ -689,18 +689,18 @@ using REG2 = registry<void, bool>; #define TEST2(NAME, ...) TEST(REG2, NAME, ##__VA_ARGS__) TEST2(test1, bool val) { - printf("REG2::test1 val %d\n", val); + printf("REG2::test1 val %d\n", val); } int main() { const auto& R1 = REG1::get(); R1.dump(); - R1.invoke("test1"); - R1.invoke("test2"); + R1.invoke("test1"); + R1.invoke("test2"); const auto& R2 = REG2::get(); R2.dump(); - R2.invoke("test1", true); + R2.invoke("test1", true); return 0; } @@ -757,7 +757,7 @@ struct Entry { }; int main() { - static_assert(is_entry_v<Entry<bool>>, ""); + static_assert(is_entry_v<Entry<bool>>, ""); } </code></pre> <p>The main mechanic can be explained with the following reduced example. If one @@ -781,7 +781,7 @@ struct A { struct B {}; -static_assert(is_valid<A>::value, "is true"); +static_assert(is_valid<A>::value, "is true"); // * Compare template arg list with primary template, we only supplied one // arg, the second one will be defaulted as // is_valid<A, void> @@ -795,7 +795,7 @@ static_assert(is_valid<A>::value, "is true"); // * Specialization (2) matches <A, void> // * Pick the most specialized version -> (2) -static_assert(!is_valid<B>::value, "is false"); +static_assert(!is_valid<B>::value, "is false"); // * Compare template arg list with primary template, we only supplied one // arg, the second one will be defaulted as // is_valid<A, void> @@ -846,7 +846,7 @@ struct pair<int, int> { }; int main() { - static_assert(pair<int>::kind == kIntBool, ""); + static_assert(pair<int>::kind == kIntBool, ""); // * Compare template arg list with primary template, we only supplied one // arg, the second one will be defaulted as // pair<int, bool> @@ -858,7 +858,7 @@ int main() { // * (4) <int, bool> pattern does not match // * Pick the most specialized version -> (3) - static_assert(pair<char, char>::kind == kTT, ""); + static_assert(pair<char, char>::kind == kTT, ""); // * Compare template arg list against available specializations, this will // try to match the pattern <char, char> against the patterns defined in the // partial specializations. @@ -867,7 +867,7 @@ int main() { // * (4) <char, char> pattern does not match // * Pick the most specialized version -> (2) - static_assert(pair<int, int>::kind == kIntInt, ""); + static_assert(pair<int, int>::kind == kIntInt, ""); // * Compare template arg list against available specializations, this will // try to match the pattern <int, int> against the patterns defined in the // partial specializations. @@ -876,7 +876,7 @@ int main() { // * (4) <int, int> pattern does not match // * Pick the most specialized version -> (3) - static_assert(pair<char, short>::kind == kPrimary, ""); + static_assert(pair<char, short>::kind == kPrimary, ""); // * Compare template arg list against available specializations, this will // try to match the pattern <char, short> against the patterns defined in the // partial specializations. @@ -897,25 +897,25 @@ struct S {}; struct M { M() { - std::puts("M()"); + std::puts("M()"); } M(const M&) { - std::puts("M(M&)"); + std::puts("M(M&)"); } M(M&&) { - std::puts("M(M&&)"); + std::puts("M(M&&)"); } M& operator=(const M&) = delete; M& operator=(M&&) = delete; M(S&, int) { - std::puts("M(S&)"); + std::puts("M(S&)"); } M(S&&, int) { - std::puts("M(S&&)"); + std::puts("M(S&&)"); } ~M() { - std::puts("~M()"); + std::puts("~M()"); } }; @@ -963,11 +963,11 @@ struct option { }; int main() { - std::puts("==> case 1"); + std::puts("==> case 1"); // invokes M(S&&, int) option<M> opt1(S{}, 123); - std::puts("==> case 2"); + std::puts("==> case 2"); // invokes M() + M(M&&) option<M> x /* option(M&&) + M(M&&) */ = M{} /* M() */; } |