Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mq卢瑟的homework2-16题 #304

Merged
merged 9 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`。** 它是一个变参模板,用来接取我们传入的任意类型和个数的参数,然后返回格式化后的字符串。

Expand Down
23 changes: 23 additions & 0 deletions src/群友提交/第02题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <format>
#include <iostream>
#include <numbers>

constexpr auto operator""_f(const char* str, size_t)
{
return [=]<typename... T>(T&& ...args)
{
return std::vformat(str, std::make_format_args(std::forward<T>(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<double>, n);
}
25 changes: 25 additions & 0 deletions src/群友提交/第03题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <iostream>
#include <format>

struct Frac {
int a, b;
};

template<typename... Args>
void print(std::string_view format_str, Args const&... args) {
std::cout << std::vformat(format_str, std::make_format_args(std::forward<decltype(args)>(args)...));
}

template<>
struct std::formatter<Frac> : std::formatter<string> {
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;
}
29 changes: 29 additions & 0 deletions src/群友提交/第04题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include<iostream>
class ComponentBase {
protected:
static inline std::size_t component_type_count = 0;
};
template<typename T>
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<A>
{};
class B : public Component<B>
{};
class C : public Component<C>
{};
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;
}
74 changes: 74 additions & 0 deletions src/群友提交/第05题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <functional>
#include <cassert>
#include <iostream>


template<typename F, typename...Args>
requires requires(F f, Args...args) { std::invoke(f, args...); }
struct scope_guard {
F f;
std::tuple<Args...>values;

scope_guard(auto&& func, auto&&...args) :f{ std::forward<decltype(func)>(func) }, values{ std::forward<decltype(args)>(args)... } {}
~scope_guard() {
std::apply(f, values);
}
scope_guard(const scope_guard&) = delete;
};

template<typename F, typename...Args>//推导指引非常重要
scope_guard(F&&, Args&&...) -> scope_guard<std::decay_t<F>, std::decay_t<Args>...>;
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);
}
}
19 changes: 19 additions & 0 deletions src/群友提交/第06题/mq卢瑟.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
`std::atomic<int> n = 6` 中,由于 `6` 和 `std::atomic<int>` 不是同一类型(但是这里其实有一个用户定义转换序列,你可以简单的认为 `6` 可以隐式转换)。

即调用转换构造函数:

```cpp
constexpr atomic( T desired ) noexcept;
```

`6` 会调用转换构造函数,构造出一个临时 `atomic<int>` 对象用来**复制初始化** `n`,即:

```cpp
std::atomic<int> n = std::atomic<int>(6);
```

根据复制消除的规则:当初始化式是纯右值时,C++17 前通常会优化掉,C++17 起始终不会进行对移动构造函数的调用。

因此在 C++17 之前的版本,理所应当应该查找检测复制/移动 构造函数,满足要求才可以通过编译。但是实际上 `atomic` 的复制构造被删除(因为三/五/零法则,移动构造也被抑制生成)了,所以自然而然地不允许。

然而在 C++17 起,复制消除变为强制要求。纯右值表达式作为构造对象的参数,不会再调用移动构造,也不会去检测,而是原位构造。
21 changes: 21 additions & 0 deletions src/群友提交/第07题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <iostream>
#include <memory>

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<std::exception>(e)->what() << '\n';
}
}
18 changes: 18 additions & 0 deletions src/群友提交/第08题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <iostream>
template<class Ty, size_t size>
struct array {
Ty* begin() { return arr; };
Ty* end() { return arr + size; };
Ty arr[size];
};

template<typename Ty, typename...Args>
requires (std::is_same_v<Ty, Args>&&...)
array(Ty, Args...)->array<Ty, sizeof...(Args) + 1>;

int main() {
::array arr{ 1, 2, 3, 4, 5 };
for (const auto& i : arr) {
std::cout << i << ' ';
}
}
13 changes: 13 additions & 0 deletions src/群友提交/第09题/mq卢瑟.md
Original file line number Diff line number Diff line change
@@ -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` 的无限定的名字查找(无法查找父类的定义),按照正常的查看顺序,先类内(查找不到),然后全局(找到)。
56 changes: 56 additions & 0 deletions src/群友提交/第10题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include <iostream>
#include <type_traits>

struct Anyth {
template <typename T>
operator T();
};

template<typename T,typename... Args>
consteval size_t size(Args&&... args)
{
static_assert(std::is_aggregate_v<T>);
if constexpr (!requires{T{ args... }; })
{
return sizeof...(args) - 1;
}
else
{
return size<T>(args..., Anyth{});
}
}

template <typename T, typename F>
void for_each_member(T const& v, F&& f) {
static_assert(std::is_aggregate_v<T>);

if constexpr (size<T>() == 4u) {
const auto& [m0, m1, m2, m3] = v;
f(m0); f(m1); f(m2); f(m3);
}
else if constexpr (size<T>() == 3u) {
const auto& [m0, m1, m2] = v;
f(m0); f(m1); f(m2);
}
else if constexpr (size<T>() == 2u) {
const auto& [m0, m1] = v;
f(m0); f(m1);
}
else if constexpr (size<T>() == 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<X>() << '\n';
std::cout << size<Y>() << '\n';

auto print = [](const auto& member) {
std::cout << member << ' ';
};
for_each_member(x, print);
for_each_member(y, print);
}
1 change: 1 addition & 0 deletions src/群友提交/第11题/mq卢瑟.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
C++20 前不允许使用 `()` 初始化聚合体。
54 changes: 54 additions & 0 deletions src/群友提交/第12题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include <cstdio>
#include <vector>

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<decltype(args)>(args)...} }; }

void test()
{
static_assert(requires {
{
make_vector(std::vector{ 1, 2, 3 })
} -> std::same_as<std::vector<std::vector<int>>>;
{
make_vector(1, 2, 3)
} -> std::same_as<std::vector<int>>;
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");
}
3 changes: 3 additions & 0 deletions src/群友提交/第13题/mq卢瑟.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1. `std::move()` 个 jb 啊,不 move 也能复制消除,move 还可能影响优化。
2. 有问题,悬垂引用。
3. 没有问题,类数据成员不是隐式可移动实体,需要通过 `std::move` 让重载决议选择移动构造。
15 changes: 15 additions & 0 deletions src/群友提交/第14题/mq卢瑟.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//!msvc
#include<iostream>

extern "C"{
namespace ss {
int a = 0;
}
}

extern "C" int a;

int main() {
a = 100;
std::cout << ss::a << '\n';
}
Loading
Loading