From bac8a5d2822835cf47175d1162030653fadd5c09 Mon Sep 17 00:00:00 2001 From: johannst Date: Thu, 15 Feb 2024 23:29:57 +0000 Subject: deploy: 4485708c972815bbb6df7f5a228683aa855d553d --- development/c++.html | 82 ++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'development/c++.html') 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.
  • On gcc strict aliasing is enabled starting with -O2.

    -
    for i in {0..3} g s; do echo "-O$i $(g++ -Q --help=optimizers -O$i | grep fstrict-aliasing)"; done
    +
    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 
     // 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');
     }
     

    Forwarding reference (fwd ref)

    @@ -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>, "");

    Example: SFINAE (enable_if)

    Provide a single entry point Invoke to call some Operations. @@ -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>>, ""); }

    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() */; } -- cgit v1.2.3