| @@ -0,0 +1,4 @@ | |||||
| .vscode | |||||
| cc/build | |||||
| */__pycache__ | |||||
| *.pyc | |||||
| @@ -0,0 +1,37 @@ | |||||
| #include "../checker.h" | |||||
| #include <vector> | |||||
| // C++ 中,`class` 和 `struct` 之间的**唯一区别**是 | |||||
| // `class` 默认访问控制符是 `private`, | |||||
| // `struct` 默认访问控制符是 `public`。 | |||||
| // READ: 访问说明符 <https://zh.cppreference.com/w/cpp/language/access> | |||||
| // 这个 class 中的字段被 private 修饰,只能在 class 内部访问。 | |||||
| // 因此必须提供构造器来初始化字段。 | |||||
| // READ: 构造器 <https://zh.cppreference.com/w/cpp/language/constructor> | |||||
| // 缓存的Fibonacci数列计算: | |||||
| // 可以考虑将之前计算好的结果保存到vector中,计算时先检查是否已经计算过,如果已经计算过, | |||||
| // 直接返回结果,反之按照递推公式进行计算 | |||||
| class Fibonacci { | |||||
| std::vector<size_t> cache; | |||||
| int cached; | |||||
| public: | |||||
| // 实现构造器 初始化Fibonacci类的某些字段 | |||||
| Fibonacci() {} | |||||
| // TODO: 实现正确的缓存优化斐波那契计算 | |||||
| size_t get(int i) { | |||||
| } | |||||
| }; | |||||
| int main() { | |||||
| // 现在类型拥有无参构造器,声明时会直接调用。 | |||||
| // 这个写法不再是未定义行为了。 | |||||
| Fibonacci fib; | |||||
| ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); | |||||
| std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| #include "../checker.h" | |||||
| // READ: 析构函数 <https://zh.cppreference.com/w/cpp/language/destructor> | |||||
| // READ: RAII <https://learn.microsoft.com/zh-cn/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170> | |||||
| // 构造任意缓存容量的斐波那契类型。 | |||||
| // 可以在构造时传入缓存容量,因此需要动态分配缓存空间。 | |||||
| class DynFibonacci { | |||||
| size_t *cache; | |||||
| int cached; | |||||
| public: | |||||
| // TODO: 实现动态设置容量的构造器 | |||||
| DynFibonacci(int capacity) {} | |||||
| // TODO: 实现析构器,释放缓存空间 | |||||
| ~DynFibonacci() {} | |||||
| // TODO: 实现正确的缓存优化斐波那契计算 | |||||
| size_t get(int i) { | |||||
| } | |||||
| }; | |||||
| int main(int argc, char **argv) { | |||||
| DynFibonacci fib(12); | |||||
| ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); | |||||
| std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| #include "../checker.h" | |||||
| #include <vector> | |||||
| // READ: 复制构造函数 <https://zh.cppreference.com/w/cpp/language/copy_constructor> | |||||
| // READ: 函数定义(显式弃置)<https://zh.cppreference.com/w/cpp/language/function> | |||||
| class Fibonacci { | |||||
| std::vector<size_t> cache; | |||||
| int cached; | |||||
| public: | |||||
| // TODO: 实现动态设置容量的构造器 | |||||
| Fibonacci(int capacity) {} | |||||
| // TODO: 实现复制构造器 | |||||
| Fibonacci(Fibonacci const &other) {} | |||||
| // TODO: 实现正确的缓存优化斐波那契计算 | |||||
| size_t get(int i) { | |||||
| } | |||||
| // NOTICE: 不要修改这个方法 | |||||
| // NOTICE: 名字相同参数也相同,但 const 修饰不同的方法是一对重载方法,可以同时存在 | |||||
| // 本质上,方法是隐藏了 this 参数的函数 | |||||
| // const 修饰作用在 this 上,因此它们实际上参数不同 | |||||
| size_t get(int i) const { | |||||
| if (i <= cached) { | |||||
| return cache[i]; | |||||
| } | |||||
| ASSERT(false, "i out of range"); | |||||
| } | |||||
| }; | |||||
| int main(int argc, char **argv) { | |||||
| Fibonacci fib(12); | |||||
| ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); | |||||
| Fibonacci const fib_ = fib; | |||||
| ASSERT(fib_.get(10) == fib.get(10), "Object cloned"); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,67 @@ | |||||
| #include "../checker.h" | |||||
| #include <vector> | |||||
| // READ: 左值右值(概念)<https://learn.microsoft.com/zh-cn/cpp/c-language/l-value-and-r-value-expressions?view=msvc-170> | |||||
| // READ: 左值右值(细节)<https://zh.cppreference.com/w/cpp/language/value_category> | |||||
| // READ: 关于移动语义 <https://learn.microsoft.com/zh-cn/cpp/cpp/rvalue-reference-declarator-amp-amp?view=msvc-170#move-semantics> | |||||
| // READ: 如果实现移动构造 <https://learn.microsoft.com/zh-cn/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170> | |||||
| // READ: 移动构造函数 <https://zh.cppreference.com/w/cpp/language/move_constructor> | |||||
| // READ: 移动赋值 <https://zh.cppreference.com/w/cpp/language/move_assignment> | |||||
| // READ: 运算符重载 <https://zh.cppreference.com/w/cpp/language/operators> | |||||
| class DynFibonacci { | |||||
| size_t *cache; | |||||
| int cached; | |||||
| public: | |||||
| // TODO: 实现动态设置容量的构造器 | |||||
| DynFibonacci(int capacity) {} | |||||
| // TODO: 实现移动构造器 | |||||
| DynFibonacci(DynFibonacci && other) { | |||||
| }; | |||||
| // TODO: 实现移动赋值 | |||||
| // NOTICE: ⚠ 注意移动到自身问题 ⚠ | |||||
| DynFibonacci &operator=(DynFibonacci && other) noexcept { | |||||
| // ASK AI: 这里的 noexcept 是什么含义? | |||||
| } | |||||
| // TODO: 实现正确的缓存优化斐波那契计算 | |||||
| // 我们重载了下标运算符,请给出正确的实现 | |||||
| size_t operator[](int i) { | |||||
| } | |||||
| // NOTICE: 不要修改这个方法 | |||||
| // THINK: 这个方法和上面的方法有什么不同? | |||||
| size_t operator[](int i) const { | |||||
| ASSERT(i <= cached, "i out of range"); | |||||
| return cache[i]; | |||||
| } | |||||
| // NOTICE: 不要修改这个方法 | |||||
| bool is_alive() const { | |||||
| return cache; | |||||
| } | |||||
| }; | |||||
| int main(int argc, char **argv) { | |||||
| DynFibonacci fib(12); | |||||
| ASSERT(fib[10] == 55, "fibonacci(10) should be 55"); | |||||
| DynFibonacci const fib_ = std::move(fib); | |||||
| ASSERT(!fib.is_alive(), "Object moved"); | |||||
| ASSERT(fib_[10] == 55, "fibonacci(10) should be 55"); | |||||
| DynFibonacci fib0(6); | |||||
| DynFibonacci fib1(12); | |||||
| fib0 = std::move(fib1); | |||||
| fib0 = std::move(fib0); | |||||
| ASSERT(fib0[10] == 55, "fibonacci(10) should be 55"); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| #include "../checker.h" | |||||
| // READ: 派生类 <https://zh.cppreference.com/w/cpp/language/derived_class> | |||||
| class Instruction { | |||||
| public: | |||||
| uint32_t raw; | |||||
| public: | |||||
| Instruction(uint32_t raw) : raw(raw) {} | |||||
| }; | |||||
| class RTypeInstruction: public Instruction { | |||||
| public: | |||||
| RTypeInstruction(uint32_t raw) : Instruction(raw) {} | |||||
| void get_rs1() { | |||||
| std::cout << ((this->raw >> 15) & 0b11111) << std::endl; | |||||
| } | |||||
| void get_rs2() { | |||||
| std::cout << ((this->raw >> 20) & 0b11111) << std::endl; | |||||
| } | |||||
| void get_rd() { | |||||
| std::cout << ((this->raw >> 7) & 0b11111) << std::endl; | |||||
| } | |||||
| std::string get_op() { | |||||
| return "Not implementaed due to unknown instruction type"; | |||||
| } | |||||
| }; | |||||
| class AddInst: public RTypeInstruction { | |||||
| public: | |||||
| AddInst(uint32_t raw) : RTypeInstruction(raw) {} | |||||
| std::string get_op() { | |||||
| return "add op"; | |||||
| } | |||||
| }; | |||||
| int main() { | |||||
| auto inst = AddInst(0x00728b33); | |||||
| inst.get_rs1(); | |||||
| inst.get_rs2(); | |||||
| inst.get_rd(); | |||||
| inst.get_op(); | |||||
| auto rinst1 = dynamic_cast<RTypeInstruction*>(&inst); | |||||
| if (rinst1) { | |||||
| // TODO: 填入正确答案 | |||||
| ASSERT(rinst1->get_op() == "", "get_op() should return " + rinst1->get_op()); | |||||
| } | |||||
| RTypeInstruction rinst2 = inst; | |||||
| // TODO: 填入正确答案 | |||||
| ASSERT(rinst2.get_op() == "", "get_op() should return " + rinst2.get_op()); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,82 @@ | |||||
| #include "../checker.h" | |||||
| // READ: 虚函数 <https://zh.cppreference.com/w/cpp/language/virtual> | |||||
| struct A { | |||||
| virtual char virtual_name() const { | |||||
| return 'A'; | |||||
| } | |||||
| char direct_name() const { | |||||
| return 'A'; | |||||
| } | |||||
| }; | |||||
| struct B : public A { | |||||
| // READ: override <https://zh.cppreference.com/w/cpp/language/override> | |||||
| char virtual_name() const override { | |||||
| return 'B'; | |||||
| } | |||||
| char direct_name() const { | |||||
| return 'B'; | |||||
| } | |||||
| }; | |||||
| struct C : public B { | |||||
| // READ: final <https://zh.cppreference.com/w/cpp/language/final> | |||||
| char virtual_name() const final { | |||||
| return 'C'; | |||||
| } | |||||
| char direct_name() const { | |||||
| return 'C'; | |||||
| } | |||||
| }; | |||||
| struct D : public C { | |||||
| char direct_name() const { | |||||
| return 'D'; | |||||
| } | |||||
| }; | |||||
| int main(int argc, char **argv) { | |||||
| constexpr auto MSG = "Replace '?' with its correct name."; | |||||
| A a; | |||||
| B b; | |||||
| C c; | |||||
| D d; | |||||
| ASSERT(a.virtual_name() == '?', MSG); | |||||
| ASSERT(b.virtual_name() == '?', MSG); | |||||
| ASSERT(c.virtual_name() == '?', MSG); | |||||
| ASSERT(d.virtual_name() == '?', MSG); | |||||
| ASSERT(a.direct_name() == '?', MSG); | |||||
| ASSERT(b.direct_name() == '?', MSG); | |||||
| ASSERT(c.direct_name() == '?', MSG); | |||||
| ASSERT(d.direct_name() == '?', MSG); | |||||
| A &rab = b; | |||||
| B &rbc = c; | |||||
| C &rcd = d; | |||||
| ASSERT(rab.virtual_name() == '?', MSG); | |||||
| ASSERT(rbc.virtual_name() == '?', MSG); | |||||
| ASSERT(rcd.virtual_name() == '?', MSG); | |||||
| ASSERT(rab.direct_name() == '?', MSG); | |||||
| ASSERT(rbc.direct_name() == '?', MSG); | |||||
| ASSERT(rcd.direct_name() == '?', MSG); | |||||
| A &rac = c; | |||||
| B &rbd = d; | |||||
| ASSERT(rac.virtual_name() == '?', MSG); | |||||
| ASSERT(rbd.virtual_name() == '?', MSG); | |||||
| ASSERT(rac.direct_name() == '?', MSG); | |||||
| ASSERT(rbd.direct_name() == '?', MSG); | |||||
| A &rad = d; | |||||
| ASSERT(rad.virtual_name() == '?', MSG); | |||||
| ASSERT(rad.direct_name() == '?', MSG); | |||||
| return 0; | |||||
| } | |||||
| // READ: 扩展阅读-纯虚、抽象 <https://zh.cppreference.com/w/cpp/language/abstract_class> | |||||
| // READ: 扩展阅读-虚继承 <https://zh.cppreference.com/w/cpp/language/derived_class> | |||||
| @@ -0,0 +1,62 @@ | |||||
| #include "../checker.h" | |||||
| struct A { | |||||
| // TODO: 正确初始化静态字段 | |||||
| static int num_a = 0; | |||||
| A() { | |||||
| ++num_a; | |||||
| } | |||||
| ~A() { | |||||
| --num_a; | |||||
| } | |||||
| virtual char name() const { | |||||
| return 'A'; | |||||
| } | |||||
| }; | |||||
| struct B final : public A { | |||||
| // TODO: 正确初始化静态字段 | |||||
| static int num_b = 0; | |||||
| B() { | |||||
| ++num_b; | |||||
| } | |||||
| ~B() { | |||||
| --num_b; | |||||
| } | |||||
| char name() const final { | |||||
| return 'B'; | |||||
| } | |||||
| }; | |||||
| int main(int argc, char **argv) { | |||||
| auto a = new A; | |||||
| auto b = new B; | |||||
| ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); | |||||
| ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); | |||||
| ASSERT(a->name() == '?', "Fill in the correct value for a->name()"); | |||||
| ASSERT(b->name() == '?', "Fill in the correct value for b->name()"); | |||||
| delete a; | |||||
| delete b; | |||||
| ASSERT(A::num_a == 0, "Every A was destroyed"); | |||||
| ASSERT(B::num_b == 0, "Every B was destroyed"); | |||||
| A *ab = new B;// 派生类指针可以随意转换为基类指针 | |||||
| ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); | |||||
| ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); | |||||
| ASSERT(ab->name() == '?', "Fill in the correct value for ab->name()"); | |||||
| // TODO: 基类指针无法随意转换为派生类指针,补全正确的转换语句 | |||||
| B &bb = *ab; | |||||
| ASSERT(bb.name() == '?', "Fill in the correct value for bb->name()"); | |||||
| // TODO: ---- 以下代码不要修改,通过改正类定义解决编译问题 ---- | |||||
| delete ab;// 通过指针可以删除指向的对象,即使是多态对象 | |||||
| ASSERT(A::num_a == 0, "Every A was destroyed"); | |||||
| ASSERT(B::num_b == 0, "Every B was destroyed"); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,112 @@ | |||||
| #include "../checker.h" | |||||
| #include <cstring> | |||||
| // READ: 类模板 <https://zh.cppreference.com/w/cpp/language/class_template> | |||||
| template<class T> | |||||
| struct Tensor4D { | |||||
| unsigned int shape[4]; | |||||
| T *data; | |||||
| Tensor4D(unsigned int const shape_[4], T const *data_) { | |||||
| unsigned int size = 1; | |||||
| // TODO: 填入正确的 shape 并计算 size | |||||
| data = new T[size]; | |||||
| std::memcpy(data, data_, size * sizeof(T)); | |||||
| } | |||||
| ~Tensor4D() { | |||||
| delete[] data; | |||||
| } | |||||
| // 为了保持简单,禁止复制和移动 | |||||
| Tensor4D(Tensor4D const &) = delete; | |||||
| Tensor4D(Tensor4D &&) noexcept = delete; | |||||
| // 这个加法需要支持“单向广播”。 | |||||
| // 具体来说,`others` 可以具有与 `this` 不同的形状,形状不同的维度长度必须为 1。 | |||||
| // `others` 长度为 1 但 `this` 长度不为 1 的维度将发生广播计算。 | |||||
| // 例如,`this` 形状为 `[1, 2, 3, 4]`,`others` 形状为 `[1, 2, 1, 4]`, | |||||
| // 则 `this` 与 `others` 相加时,3 个形状为 `[1, 2, 1, 4]` 的子张量各自与 `others` 对应项相加。 | |||||
| Tensor4D &operator+=(Tensor4D const &others) { | |||||
| // TODO: 实现单向广播的加法 | |||||
| // check whether a dimension needs broadcast | |||||
| return *this; | |||||
| } | |||||
| }; | |||||
| // ---- 不要修改以下代码 ---- | |||||
| int main(int argc, char **argv) { | |||||
| { | |||||
| unsigned int shape[]{1, 2, 3, 4}; | |||||
| // clang-format off | |||||
| int data[]{ | |||||
| 1, 2, 3, 4, | |||||
| 5, 6, 7, 8, | |||||
| 9, 10, 11, 12, | |||||
| 13, 14, 15, 16, | |||||
| 17, 18, 19, 20, | |||||
| 21, 22, 23, 24}; | |||||
| // clang-format on | |||||
| auto t0 = Tensor4D(shape, data); | |||||
| auto t1 = Tensor4D(shape, data); | |||||
| t0 += t1; | |||||
| for (auto i = 0u; i < sizeof(data) / sizeof(*data); ++i) { | |||||
| ASSERT(t0.data[i] == data[i] * 2, "Tensor doubled by plus its self."); | |||||
| } | |||||
| } | |||||
| { | |||||
| unsigned int s0[]{1, 2, 3, 4}; | |||||
| // clang-format off | |||||
| float d0[]{ | |||||
| 1, 1, 1, 1, | |||||
| 2, 2, 2, 2, | |||||
| 3, 3, 3, 3, | |||||
| 4, 4, 4, 4, | |||||
| 5, 5, 5, 5, | |||||
| 6, 6, 6, 6}; | |||||
| // clang-format on | |||||
| unsigned int s1[]{1, 2, 3, 1}; | |||||
| // clang-format off | |||||
| float d1[]{ | |||||
| 6, | |||||
| 5, | |||||
| 4, | |||||
| 3, | |||||
| 2, | |||||
| 1}; | |||||
| // clang-format on | |||||
| auto t0 = Tensor4D(s0, d0); | |||||
| auto t1 = Tensor4D(s1, d1); | |||||
| t0 += t1; | |||||
| for (auto i = 0u; i < sizeof(d0) / sizeof(*d0); ++i) { | |||||
| ASSERT(t0.data[i] == 7.f, "Every element of t0 should be 7 after adding t1 to it."); | |||||
| } | |||||
| } | |||||
| { | |||||
| unsigned int s0[]{1, 2, 3, 4}; | |||||
| // clang-format off | |||||
| double d0[]{ | |||||
| 1, 2, 3, 4, | |||||
| 5, 6, 7, 8, | |||||
| 9, 10, 11, 12, | |||||
| 13, 14, 15, 16, | |||||
| 17, 18, 19, 20, | |||||
| 21, 22, 23, 24}; | |||||
| // clang-format on | |||||
| unsigned int s1[]{1, 1, 1, 1}; | |||||
| double d1[]{1}; | |||||
| auto t0 = Tensor4D(s0, d0); | |||||
| auto t1 = Tensor4D(s1, d1); | |||||
| t0 += t1; | |||||
| for (auto i = 0u; i < sizeof(d0) / sizeof(*d0); ++i) { | |||||
| ASSERT(t0.data[i] == d0[i] + 1, "Every element of t0 should be incremented by 1 after adding t1 to it."); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| #ifndef __EXERCISE_H__ | |||||
| #define __EXERCISE_H__ | |||||
| #include <iostream> | |||||
| #define ASSERT(COND, MSG) \ | |||||
| if (!(COND)) { \ | |||||
| std::cerr << "\x1b[31mAssertion failed at line #" << __LINE__ << ": \x1b[0m" << std::endl \ | |||||
| << std::endl \ | |||||
| << #COND << std::endl \ | |||||
| << std::endl \ | |||||
| << "\x1b[34mMessage:\x1b[0m" << std::endl \ | |||||
| << std::endl \ | |||||
| << MSG << std::endl \ | |||||
| << std::endl; \ | |||||
| exit(1); \ | |||||
| } | |||||
| #endif// __EXERCISE_H__ | |||||
| @@ -0,0 +1,11 @@ | |||||
| #include <iostream> | |||||
| constexpr int fibonacci(const int n) { | |||||
| return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2); | |||||
| } | |||||
| int main(){ | |||||
| int fib_5 = fibonacci(5); | |||||
| std::cout << "fib 5: " << fib_5 << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| #include <iostream> | |||||
| #include <tuple> | |||||
| std::tuple<int, double, std::string> get_data() { | |||||
| return std::make_tuple(1, 2.71828, "hello"); | |||||
| } | |||||
| int main() { | |||||
| auto [a, b, c] = get_data(); | |||||
| std::cout << a << " " << b << " " << c << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,10 @@ | |||||
| #include <iostream> | |||||
| #include <vector> | |||||
| int main() { | |||||
| std::vector<int> vec; | |||||
| std::vector<int>::const_iterator a = vec.cbegin(); | |||||
| // using type inference | |||||
| auto b = vec.cbegin(); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| #include <iostream> | |||||
| int main() { | |||||
| auto x = 1; | |||||
| auto y = 2.0; | |||||
| decltype(x+y) z; | |||||
| if (std::is_same<decltype(x+y), double>::value) { | |||||
| std::cout << "x+y is double" << std::endl; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| #include <iostream> | |||||
| template<typename T> | |||||
| T add(T a, T b) { | |||||
| return a + b; | |||||
| } | |||||
| int main() { | |||||
| double a = 1.0; | |||||
| double b = 2.0; | |||||
| std::cout << add<double>(a, b) << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| #include <iostream> | |||||
| template<typename T, typename U> | |||||
| auto add(T x, U y){ | |||||
| return x + y; | |||||
| } | |||||
| int main() { | |||||
| int a = 1; | |||||
| double b = 2.71828; | |||||
| std::cout << add(a, b) << std::endl; | |||||
| if (std::is_same<decltype(add(a, b)), double>::value) { | |||||
| std::cout << "result type of add(a, b) is double!" << std::endl; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| #include <iostream> | |||||
| template<typename... Ts> | |||||
| void magic(Ts... args) { | |||||
| std::cout << sizeof...(args) << std::endl; | |||||
| } | |||||
| int main() { | |||||
| magic(); | |||||
| magic(1); | |||||
| magic(1, 2); | |||||
| magic(1, "hello", "world"); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| #include <iostream> | |||||
| template<typename T> | |||||
| void my_printf(T value) { | |||||
| std::cout << value << std::endl; | |||||
| } | |||||
| template<typename T, typename... Ts> | |||||
| void my_printf(T value, Ts... args) { | |||||
| std::cout << value << std::endl; | |||||
| my_printf(args...); | |||||
| } | |||||
| int main() { | |||||
| my_printf(1, 2, "San Francisco", 1.1); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| #include <iostream> | |||||
| template<typename T, typename... Ts> | |||||
| void my_printf(T t0, Ts... t) { | |||||
| std::cout << t0 << std::endl; | |||||
| if constexpr (sizeof...(t) > 0) my_printf(t...); | |||||
| } | |||||
| int main() { | |||||
| my_printf(1, 2, "San Francisco", 1.1); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| #include <iostream> | |||||
| #include <vector> | |||||
| int main() { | |||||
| std::vector<int> v = {1, 2, 3, 4, 5}; | |||||
| for (auto it: v) { | |||||
| std::cout << it << std::endl; | |||||
| } | |||||
| for (auto &it: v) { | |||||
| it = it * 2; | |||||
| } | |||||
| for (auto it: v) { | |||||
| std::cout << it << std::endl; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| template<class T> | |||||
| struct point { | |||||
| T x; | |||||
| T y; | |||||
| }; | |||||
| point<double> p1{1.0, 2.0}; | |||||
| point<int> p2{1, 2}; | |||||
| @@ -0,0 +1,19 @@ | |||||
| #include <iostream> | |||||
| // define a template for calculating factorial | |||||
| template<int N> | |||||
| struct Factorial { | |||||
| static const int value = N * Factorial<N - 1>::value; | |||||
| }; | |||||
| // specialized template to end the factorial recursive | |||||
| template<> | |||||
| struct Factorial<0> { | |||||
| static const int value = 1; | |||||
| }; | |||||
| int main() { | |||||
| std::cout << "Factorial of 5 is: " << Factorial<5>::value << std::endl; | |||||
| std::cout << "Factorial of 10 is: " << Factorial<10>::value << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| #include <algorithm> | |||||
| #include <iostream> | |||||
| #include <vector> | |||||
| struct CppRecord { | |||||
| size_t id; | |||||
| double value; | |||||
| }; | |||||
| int main() { | |||||
| std::vector<CppRecord> records = { | |||||
| {1, 3.5}, | |||||
| {2, 2.0}, | |||||
| {3, 3.5}, | |||||
| {4, 1.0}, | |||||
| {5, 2.0}}; | |||||
| std::sort(records.begin(), records.end(), [](const CppRecord& a, const CppRecord& b) { | |||||
| if (a.value != b.value) { | |||||
| return a.value < b.value; | |||||
| } else { | |||||
| return a.id < b.id; | |||||
| } | |||||
| }); | |||||
| for (const auto& record : records) { | |||||
| std::cout << record.id << " " << record.value << std::endl; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| #include <iostream> | |||||
| int main() { | |||||
| auto add = [](auto x, auto y) { | |||||
| return x+y; | |||||
| }; | |||||
| auto r1 = add(1, 2); | |||||
| auto r2 = add(1.1, 2.2); | |||||
| std::cout << r1 << " " << r2 << std::endl; | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| #include <iostream> | |||||
| #include <functional> | |||||
| #include <vector> | |||||
| // define a higher order function, composing all functions together | |||||
| template<typename T> | |||||
| std::function<T(T)> compose(std::vector<std::function<T(T)>> functions) { | |||||
| return [functions](T x) { | |||||
| T result = x; | |||||
| // apply all these function from the right to the left | |||||
| for (auto it = functions.rbegin(); it != functions.rend(); ++it) { | |||||
| result = (*it)(result); | |||||
| } | |||||
| return result; | |||||
| }; | |||||
| } | |||||
| int main() { | |||||
| // define a couple of simple functions | |||||
| auto add_one = [](int x) { return x + 1; }; | |||||
| auto square = [](int x) { return x * x; }; | |||||
| auto double_value = [](int x) { return x * 2; }; | |||||
| // compose the functions | |||||
| std::vector<std::function<int(int)>> functions = {double_value, square, add_one}; | |||||
| auto pipeline = compose(functions); | |||||
| // test the composed functions | |||||
| int result = pipeline(3); | |||||
| std::cout << result << std::endl; // output: 32 | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| a = [42, 23, -17, 11, -8, 15, -38, 23, 18, -1] | |||||
| # sort by absolute value | |||||
| a.sort(key=lambda x: abs(x)) | |||||
| print(a) | |||||
| @@ -0,0 +1,13 @@ | |||||
| # define a higher order function | |||||
| # note: this function receives a function as an argument | |||||
| def apply_twice(func, x): | |||||
| # note: this function returns a function | |||||
| return func(func(x)) | |||||
| # define a simple function | |||||
| def square(x): | |||||
| return x * x | |||||
| # use this higher order function | |||||
| result = apply_twice(square, 2) | |||||
| print(result) # output: 16 | |||||
| @@ -0,0 +1,12 @@ | |||||
| #include <memory> | |||||
| #include <iostream> | |||||
| void foo(std::shared_ptr<int> p) { | |||||
| (*p)++; | |||||
| } | |||||
| void create() { | |||||
| std::shared_ptr<int> p = std::make_shared<int>(42); | |||||
| foo(p); | |||||
| // p is still valid | |||||
| std::cout << *p << std::endl; | |||||
| } // when leaving this scope, p will be destroyed (deleted) | |||||
| @@ -0,0 +1,15 @@ | |||||
| import gc | |||||
| class FooClass: | |||||
| def __init__(self): | |||||
| self.value = 1 | |||||
| def __del__(self): | |||||
| print(f"FooClass {id(self)} destroyed!") | |||||
| foo1 = FooClass() | |||||
| foo2 = foo1 | |||||
| del foo1 | |||||
| print("Called del foo1") | |||||
| gc.collect() | |||||
| foo2.value += 1 | |||||
| print("Called foo2.value += 1") | |||||
| @@ -0,0 +1,10 @@ | |||||
| import sys | |||||
| a = [1, 2, 3] | |||||
| print(f"a's reference count: {sys.getrefcount(a)}") | |||||
| b = a | |||||
| print(f"a's reference count: {sys.getrefcount(a)}") | |||||
| print(f"b's reference count: {sys.getrefcount(b)}") | |||||
| del b | |||||
| print(f"a's reference count: {sys.getrefcount(a)}") | |||||
| del a | |||||
| print(f"a's reference count: {sys.getrefcount(a)}") | |||||