diff --git a/README.md b/README.md index df0ce97e..f14003f7 100644 --- a/README.md +++ b/README.md @@ -439,7 +439,7 @@ impl::Helper operator""_f(const char* s, std::size_t len) noexcept { } ``` -`operator""_f` 本身非常简单,只是用来把传入的参数(格式字符串)和长度,构造 `mpl::Helper` 对象再返回。`Helper` 类型使用了一个 `string_veiw` 作为数据成员,存储了格式字符串,以供后面格式化使用。 +`operator""_f` 本身非常简单,只是用来把传入的参数(格式字符串)和长度,构造 `impl::Helper` 对象再返回。`Helper` 类型使用了一个 `string_view` 作为数据成员,存储了格式字符串,以供后面格式化使用。 **重点只在于 `operator()`。** 它是一个变参模板,用来接取我们传入的任意类型和个数的参数,然后返回格式化后的字符串。 diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25402\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25402\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..974cbb73 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25402\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,23 @@ +#include +#include +#include + +constexpr auto operator""_f(const char* str, size_t) +{ + return [=](T&& ...args) + { + return std::vformat(str, std::make_format_args(std::forward(args)...)); + }; +} + +int main() { + + std::cout << "乐 :{} *\n"_f(5); + std::cout << "乐 :{0} {0} *\n"_f(5); + std::cout << "乐 :{:b} *\n"_f(0b01010101); + std::cout << "{:*<10}"_f("卢瑟"); + std::cout << '\n'; + int n{}; + std::cin >> n; + std::cout << "π:{:.{}f}\n"_f(std::numbers::pi_v, n); +} diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25403\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25403\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..430e5c26 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25403\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,25 @@ +#include +#include + +struct Frac { + int a, b; +}; + +template +void print(std::string_view format_str, Args const&... args) { + std::cout << std::vformat(format_str, std::make_format_args(std::forward(args)...)); +} + +template<> +struct std::formatter : std::formatter { + auto format(Frac const& f, auto& ctx) const { + return std::format_to(ctx.out(), "{}/{}", f.a, f.b); + } +}; + +int main() { + const Frac f{ 1, 10 }; + print("{}", f); + + return 0; +} diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25404\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25404\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..0b5d617a --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25404\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,29 @@ +#include +class ComponentBase { +protected: + static inline std::size_t component_type_count = 0; +}; +template +class Component : public ComponentBase { +public: + static std::size_t component_type_id() { + static std::size_t id = component_type_count++; + return id; + } +}; + +class A : public Component +{}; +class B : public Component +{}; +class C : public Component +{}; +int main() +{ + std::cout << A::component_type_id() << std::endl; + std::cout << B::component_type_id() << std::endl; + std::cout << B::component_type_id() << std::endl; + std::cout << A::component_type_id() << std::endl; + std::cout << A::component_type_id() << std::endl; + std::cout << C::component_type_id() << std::endl; +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25405\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25405\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..633787b8 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25405\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,74 @@ +#include +#include +#include + + +template + requires requires(F f, Args...args) { std::invoke(f, args...); } +struct scope_guard { + F f; + std::tuplevalues; + + scope_guard(auto&& func, auto&&...args) :f{ std::forward(func) }, values{ std::forward(args)... } {} + ~scope_guard() { + std::apply(f, values); + } + scope_guard(const scope_guard&) = delete; +}; + +template//推导指引非常重要 +scope_guard(F&&, Args&&...) -> scope_guard, std::decay_t...>; +struct X { + X() { puts("X()"); } + X(const X&) { puts("X(const X&)"); } + X(X&&) noexcept { puts("X(X&&)"); } + ~X() { puts("~X()"); } +}; + +int main() { + + { + // scope_guard的作用之一,是让各种C风格指针接口作为局部变量时也能得到RAII支持 + // 这也是本题的基础要求 + FILE* fp = nullptr; + try { + fp = fopen("test.txt", "a"); + auto guard = scope_guard([&] { + fclose(fp); + fp = nullptr; + }); + + throw std::runtime_error{ "Test" }; + } + catch (std::exception& e) { + puts(e.what()); + } + assert(fp == nullptr); + } + puts("----------"); + { + // 附加要求1,支持函数对象调用 + struct Test { + void operator()(X* x) { + delete x; + } + } t; + auto x = new X{}; + auto guard = scope_guard(t, x); + } + puts("----------"); + { + // 附加要求2,支持成员函数和std::ref + auto x = new X{}; + { + struct Test { + void f(X*& px) { + delete px; + px = nullptr; + } + } t; + auto guard = scope_guard{ &Test::f, &t, std::ref(x) }; + } + assert(x == nullptr); + } +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25406\351\242\230/mq\345\215\242\347\221\237.md" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25406\351\242\230/mq\345\215\242\347\221\237.md" new file mode 100644 index 00000000..8d295ad0 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25406\351\242\230/mq\345\215\242\347\221\237.md" @@ -0,0 +1,19 @@ +`std::atomic n = 6` 中,由于 `6` 和 `std::atomic` 不是同一类型(但是这里其实有一个用户定义转换序列,你可以简单的认为 `6` 可以隐式转换)。 + +即调用转换构造函数: + +```cpp +constexpr atomic( T desired ) noexcept; +``` + +`6` 会调用转换构造函数,构造出一个临时 `atomic` 对象用来**复制初始化** `n`,即: + +```cpp +std::atomic n = std::atomic(6); +``` + +根据复制消除的规则:当初始化式是纯右值时,C++17 前通常会优化掉,C++17 起始终不会进行对移动构造函数的调用。 + +因此在 C++17 之前的版本,理所应当应该查找检测复制/移动 构造函数,满足要求才可以通过编译。但是实际上 `atomic` 的复制构造被删除(因为三/五/零法则,移动构造也被抑制生成)了,所以自然而然地不允许。 + +然而在 C++17 起,复制消除变为强制要求。纯右值表达式作为构造对象的参数,不会再调用移动构造,也不会去检测,而是原位构造。 diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25407\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25407\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..dc470194 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25407\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,21 @@ +#include +#include + +struct MyException :std::exception { + const char* data{}; + MyException(const char* s) :data(s) { puts("MyException()"); } + ~MyException() { puts("~MyException()"); } + const char* what()const noexcept { return data; } +}; +void f2() { + throw new MyException("new Exception异常...."); +} +int main() { + try { + f2(); + } + catch (std::exception *e) + { + std::cout << std::unique_ptr(e)->what() << '\n'; + } +} diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25408\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25408\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..823e34d1 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25408\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,18 @@ +#include +template +struct array { + Ty* begin() { return arr; }; + Ty* end() { return arr + size; }; + Ty arr[size]; +}; + +template + requires (std::is_same_v&&...) +array(Ty, Args...)->array; + +int main() { + ::array arr{ 1, 2, 3, 4, 5 }; + for (const auto& i : arr) { + std::cout << i << ' '; + } +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25409\351\242\230/mq\345\215\242\347\221\237.md" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25409\351\242\230/mq\345\215\242\347\221\237.md" new file mode 100644 index 00000000..efc2a82a --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25409\351\242\230/mq\345\215\242\347\221\237.md" @@ -0,0 +1,13 @@ +**已知:** + +> 对于在模板的定义中所使用的非待决名,当检查该模板的定义时将进行无限定的名字查找。在这个位置与声明之间的绑定并不会受到在实例化点可见的声明的影响。 而对于在模板定义中所使用的待决名,它的查找会推迟到得知它的模板实参之时。 此时,ADL 将同时在模板的定义语境和在模板的实例化语境中检查可见的具有外部连接的(C++11 前)函数声明,而非 ADL 的查找只会检查在模板的定义语境中可见的具有外部连接的(C++11 前)函数声明。 (换句话说,在模板定义之后添加新的函数声明,除非通过 ADL 否则仍是不可见的。) 如果在 ADL 查找所检查的命名空间中,在某个别的翻译单元中声明了一个具有外部连接的更好的匹配声明,或者如果当同样检查这些翻译单元时其查找会导致歧义,那么行为未定义。 无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。 + +这里的最后一句话比较迷惑:**无论哪种情况,如果某个基类取决于某个模板形参,那么无限定名字查找不会检查它的作用域(在定义点和实例化点都不会)。** + +因为 `this->f()` 也是无限定的。但这里确实查找到了基类的 `f()` 函数。对此 *mq 白* 给出的解释是:因为 `f` 是待决名,查找会推迟到得知它模板实参之时,此时父类不再取决于模板形参,已经实例化了,就没有上面说的那个问题了。 + +**因此:** + +`t()` 中的 `this->f()` 是无限定的待决调用,会在明确它的模板实参之时再次进行关于 `f` 的名字查找,并且会查找基类,因此找到了基类的成员函数 `f()`。 + +`t2()` 中的 `f()` 是无限定的非待决调用,检查该模板的定义时将进行关于 `f` 的无限定的名字查找(无法查找父类的定义),按照正常的查看顺序,先类内(查找不到),然后全局(找到)。 diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25410\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25410\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..53c97d52 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25410\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,56 @@ +#include +#include + +struct Anyth { + template + operator T(); +}; + +template +consteval size_t size(Args&&... args) +{ + static_assert(std::is_aggregate_v); + if constexpr (!requires{T{ args... }; }) + { + return sizeof...(args) - 1; + } + else + { + return size(args..., Anyth{}); + } +} + +template +void for_each_member(T const& v, F&& f) { + static_assert(std::is_aggregate_v); + + if constexpr (size() == 4u) { + const auto& [m0, m1, m2, m3] = v; + f(m0); f(m1); f(m2); f(m3); + } + else if constexpr (size() == 3u) { + const auto& [m0, m1, m2] = v; + f(m0); f(m1); f(m2); + } + else if constexpr (size() == 2u) { + const auto& [m0, m1] = v; + f(m0); f(m1); + } + else if constexpr (size() == 1u) { + const auto& [m0] = v; + f(m0); + } +} + +int main() { + struct X { std::string s{ " " }; }x; + struct Y { double a{}, b{}, c{}, d{}; }y; + std::cout << size() << '\n'; + std::cout << size() << '\n'; + + auto print = [](const auto& member) { + std::cout << member << ' '; + }; + for_each_member(x, print); + for_each_member(y, print); +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25411\351\242\230/mq\345\215\242\347\221\237.md" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25411\351\242\230/mq\345\215\242\347\221\237.md" new file mode 100644 index 00000000..a53b21fa --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25411\351\242\230/mq\345\215\242\347\221\237.md" @@ -0,0 +1 @@ +C++20 前不允许使用 `()` 初始化聚合体。 diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25412\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25412\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..6d945619 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25412\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,54 @@ +#include +#include + +inline void dbg(const char* msg) +{ + std::puts(msg); + std::fflush(stdout); +} + +struct X { + X() noexcept + { + dbg("X()"); + }; + + ~X() noexcept + { + dbg("~X()"); + }; + + X(const X&) + { + dbg("X(const X&)"); + } + + X(X&&) noexcept + { + dbg("X(X&&)"); + } +}; + +constexpr auto make_vector(auto&& ...args) { return std::vector{ {std::forward(args)...} }; } + +void test() +{ + static_assert(requires { + { + make_vector(std::vector{ 1, 2, 3 }) + } -> std::same_as>>; + { + make_vector(1, 2, 3) + } -> std::same_as>; + make_vector(1, 2, 3).size() == 3; + }); + X x1; + X x2; + auto vec = make_vector(x1, std::move(x2)); +} + +int main() +{ + test(); + dbg("test end"); +} diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25413\351\242\230/mq\345\215\242\347\221\237.md" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25413\351\242\230/mq\345\215\242\347\221\237.md" new file mode 100644 index 00000000..3dbc6abb --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25413\351\242\230/mq\345\215\242\347\221\237.md" @@ -0,0 +1,3 @@ +1. `std::move()` 个 jb 啊,不 move 也能复制消除,move 还可能影响优化。 +2. 有问题,悬垂引用。 +3. 没有问题,类数据成员不是隐式可移动实体,需要通过 `std::move` 让重载决议选择移动构造。 diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25414\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25414\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..390f4b92 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25414\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,15 @@ +//!msvc +#include + +extern "C"{ + namespace ss { + int a = 0; + } +} + +extern "C" int a; + +int main() { + a = 100; + std::cout << ss::a << '\n'; +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25415\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25415\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..15fe8c1d --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25415\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include + +// 为std::vector增加一个自定义的赋值函数 +template + requires std::disjunction_v, std::is_floating_point> +class vector : public std::vector { +public: + using std::vector::vector; + using std::vector::size; + using std::vector::operator[]; + template + vector& operator=(const E& e) + { + const auto count = std::min(size(), e.size()); + this->resize(count); + for (std::size_t idx { 0 }; idx < count; ++idx) { + this->operator[](idx) = e[idx]; + } + return *this; + } +}; + +// 表达式模板类 +template +class vector_expr { + const Lhs& lhs; + const Rhs& rhs; + +public: + vector_expr(const Lhs& l, const Rhs& r) : lhs(l), rhs(r) {} + + auto operator[](std::size_t idx) const { + return Op::apply(lhs[idx], rhs[idx]); + } + + std::size_t size() const { + return std::min(lhs.size(), rhs.size()); + } +}; + +// 运算符重载 +struct Add { + template + static T apply(const T& lhs, const T& rhs) { + return lhs + rhs; + } +}; + +struct Subtract { + template + static T apply(const T& lhs, const T& rhs) { + return lhs - rhs; + } +}; + +struct Multiply { + template + static T apply(const T& lhs, const T& rhs) { + return lhs * rhs; + } +}; + +struct Divide { + template + static T apply(const T& lhs, const T& rhs) { + return lhs / rhs; + } +}; + +template +auto operator+(const Lhs& lhs, const Rhs& rhs) { + return vector_expr(lhs, rhs); +} + +template +auto operator-(const Lhs& lhs, const Rhs& rhs) { + return vector_expr(lhs, rhs); +} + +template +auto operator*(const Lhs& lhs, const Rhs& rhs) { + return vector_expr(lhs, rhs); +} + +template +auto operator/(const Lhs& lhs, const Rhs& rhs) { + return vector_expr(lhs, rhs); +} + +int main() +{ + auto print = [](const auto& v) { + std::ranges::copy(v, std::ostream_iterator> { std::cout, ", " }); + std::cout << std::endl; + }; + const vector a { 1.2764, 1.3536, 1.2806, 1.9124, 1.8871, 1.7455 }; + const vector b { 2.1258, 2.9679, 2.7635, 2.3796, 2.4820, 2.4195 }; + const vector c { 3.9064, 3.7327, 3.4760, 3.5705, 3.8394, 3.8993 }; + const vector d { 4.7337, 4.5371, 4.5517, 4.2110, 4.6760, 4.3139 }; + const vector e { 5.2126, 5.1452, 5.8678, 5.1879, 5.8816, 5.6282 }; + + { + vector result(6); + for (std::size_t idx = 0; idx < 6; idx++) { + result[idx] = a[idx] - b[idx] * c[idx] / d[idx] + e[idx]; + } + print(result); + } + { + vector result(6); + result = a - b * c / d + e; // 使用表达式模板计算 + print(result); + } + return 0; +} \ No newline at end of file diff --git "a/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25416\351\242\230/mq\345\215\242\347\221\237.cxx" "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25416\351\242\230/mq\345\215\242\347\221\237.cxx" new file mode 100644 index 00000000..b27c4a99 --- /dev/null +++ "b/src/\347\276\244\345\217\213\346\217\220\344\272\244/\347\254\25416\351\242\230/mq\345\215\242\347\221\237.cxx" @@ -0,0 +1,17 @@ +#include + +#define BY_NAME(func) \ +[](auto&&... args) \ +{ \ + return func(std::forward(args)...); \ +} + +template +auto foo(F f, Args&&...args) { + return f(std::forward(args)...); +} + +int main() { + const auto result = foo(BY_NAME(std::min), 2, 3); + std::cout << result << '\n'; +} \ No newline at end of file