首页
留言
关于
统计
友链
Search
1
[C++Quiz]#4、#116、#174
1 阅读
2
C/C++选手初学Python可能遇到的问题
0 阅读
3
[C++Quiz]#27、#41、#44
0 阅读
4
[C++Quiz]#185、#207、#219
0 阅读
5
[C++]std::variant
0 阅读
C/C++
数据结构与算法
CSLab
xv6
bustub
6.5840
数据库
doris
SQL
做个数据库
工具
CS
登录
Search
标签搜索
C++
cppquiz
xv6
算法
doris
论文
os
CS
leetcode
Git
tools
并发
6.5840
Koarz
累计撰写
24
篇文章
累计收到
4
条评论
首页
栏目
C/C++
数据结构与算法
CSLab
xv6
bustub
6.5840
数据库
doris
SQL
做个数据库
工具
CS
页面
留言
关于
统计
友链
搜索到
15
篇与
的结果
2023-07-15
[C++]std::variant
{dotted startColor="#ff6c6c" endColor="#1989fa"/}std::variant介绍{message type="info" content="以下信息参考cppreference"/}{card-list}{card-list-item}在标头 定义{/card-list-item}{card-list-item}template <class... Types>class variant; (C++17 起) {/card-list-item}{/card-list}类模板 std::variant 表示一个类型安全的联合体。 std::variant 的一个实例在任意时刻要么保有其一个可选类型之一的值,要么在错误情况下无值(此状态难以达成,见 valueless_by_exception )。与联合体在聚合初始化中的行为一致, 若 variant 保有某个对象类型 T 的值,则直接于 variant 的对象表示中分配 T 的对象表示。不允许 variant 分配额外的(动态)内存。variant 不容许保有引用、数组,或类型 void 。空 variant 亦为病式(可用 std::variant<std::monostate> 代替)。variant 容许保有同一类型多于一次,而且可保有同一类型的不同 cv 限定版本。同联合体,默认构造的 variant 保有其首个选项的值,除非该选项不是可默认构造的(该情况下 variant 亦非可默认构造:能用辅助类 std::monostate 使这种 variant 可默认构造)。{card-describe title="模板形参"}Types - 可存储于此 variant 中的类型。所有类型必须满足可析构 (Destructible) 要求(特别是不允许数组类型和非对象类型)。 {/card-describe}std::variant的简单使用#include <iostream> #include <variant> using var_T = std::variant<int,double,char>; int main() { var_T v; v = 1;//给v复制int std::cout << std::get<int>(v) << ' ' << v.index() << '\n'; v = 2.5;//给v赋值double std::cout << std::get<double>(v) << ' ' << v.index() << '\n'; v = 'A';//给v赋值char std::cout << std::get<char>(v) << ' ' << v.index() << '\n'; v = "Hello cremache!" //error,v不能储存字符串类型 return 0; }输出:1 02.5 1A 2分析:示例给的 variant 可以储存int,double,char类型的数据,如果我们需要将v储存的值输出,那么就需要用到std::get<type>(var),但是这种输出需要你显式指出v储存的值的类型,auto 在这里是不能使用的,当然除了具体的数据类型,你也可以使用 0 代表 int ,1 代表 double ,2 代表 char(具体请根据你自己的定义,这里的012是根据我的定义)。除了std::get() C++还提供了std::get_if() ,get_if 同样需要显式指出数据类型,get_if的参数是指向 variant 的指针,返回值是指向存储于被指向的 variant 中值的指针,错误时为空指针。index()可以返回 variant 当前所保有的可选项的零基下标。若 variant 因异常无值( valueless_by_exception ),则返回 variant_npos 。通俗来说就是0是int,1是double(仅限示例)。{alert type="error"}需要额外注意的是如果你想这样使用std::get<v.index()>(v)那么就停留在想阶段,这样的代码是错误的。{/alert}在std::vector中使用std::variant#include <iostream> #include <variant> #include <vector> using var_T = std::variant<int,double,char>; template<class... Ts> struct overloaded : Ts... {using Ts::operator()...;}; template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; int main() { std::vector<var_T> n{ 2.5 , 'A', 1}; for(auto v : n) { std::visit(overloaded{ [](int arg) { std::cout << arg; }, [](double arg) {std::cout << std::fixed << arg;}, [](char arg) {std::cout << arg;}, },v); std::cout << '\n'; } return 0; }输出:2.50000A1这是cppreference给出的写法,我们需要使用visit()函数来访问数据,但是这种写法非常麻烦,这里有一个难懂的overloaded 在 Stack Overflow 中有大佬对overloaded做出解释:{alert type="info"}第一个 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; 是一个经典的类/结构声明/定义/实现。从C++11开始有效(因为使用了可变模板)。 在这种情况下,overloaded从所有模板参数继承,并使用了所有继承的operator()(使用了using语句)。这是Variadic CRTP的一个示例。 不幸的是,可变using语句只在C++17及以上版本中可用。 第二个 template<class... Ts> overloaded(Ts...) -> overloaded<Ts...> 是一个“推导指南”(详见此页面了解更多详情),它是C++17的一个新特性。 在你的情况下,推导指南表示当你写下如下代码时: auto ov = overloaded{ arg1, arg2, arg3, arg4 }; 或者 overloaded ov{ arg1, args, arg3, arg4 }; ov变成了overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)> 这允许你写出如下代码:overloaded { [](int arg) { std::cout << arg; }, [](double arg) {std::cout << std::fixed << arg;}, [](char arg) {std::cout << arg;}, } 在示例代码中还有另一个有趣的新C++17特性:基类的聚合初始化。 也就是说...当你写下如下代码时:overloaded { [](int arg) { std::cout << arg; }, [](double arg) {std::cout << std::fixed << arg;}, [](char arg) {std::cout << arg;}, }你是在初始化overloaded的三个基类时传递了三个lambda函数。 在C++17之前,只有在编写了显式构造函数时才能这样做。从C++17开始,它可以自动工作。 {/alert}但是这种写法我们可以简化!#include <iostream> #include <variant> #include <vector> using var_T = std::variant<int,double,char>; int main() { std::vector<var_T> n{ 2.5 , 'A', 1}; for(auto v : n) { std::visit([](auto arg){std::cout << arg;},v); std::cout << '\n'; } return 0; }直接使用使用auto推导类型,就不用我们分情况写了。当然,具体操作还是得根据具体情况使用。
2023年07月15日
0 阅读
0 评论
0 点赞
2023-07-13
[C++Quiz]#4、#116、#174
Question #174{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include<iostream> void f(int& a, const int& b) { std::cout << b; a = 1; std::cout << b; } int main(){ int x = 0; f(x,x); }{card-default label="答案及解析:" width=""}01b是一个const引用,我们不能修改它,但是不能保证它不会被其他地方修改,a也是x的别名,所以可以通过a修改x使b中的值改变。{/card-default}Question #4 {card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> void f(float) { std::cout << 1; } void f(double) { std::cout << 2; } int main() { f(2.5); f(2.5f); }{card-default label="答案及解析:" width=""}21emmm...过。{/card-default}Question #116{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> #include <utility> int y(int &) { return 1; } int y(int &&) { return 2; } template <class T> int f(T &&x) { return y(x); } template <class T> int g(T &&x) { return y(std::move(x)); } template <class T> int h(T &&x) { return y(std::forward<T>(x)); } int main() { int i = 10; std::cout << f(i) << f(20); std::cout << g(i) << g(20); std::cout << h(i) << h(20); return 0; }{card-default label="答案及解析:" width=""}112212T&&看起来像右值引用但是在函数模板中它其实是通用引用,它取决于用于实例化模板的类型。如果使用左值实例化,它会折叠成左值引用;如果使用右值实例化,它会折叠成右值引用。对于f函数,虽然参数20是右值,但是x始终是左值(尽管它本身是右值引用),所以无论是传入i还是20都会匹配到y(int &),g函数中move(x)会得到右值引用,所以两次都调用了y(int &&),std::forward(x)会保留原数据类型,i是左值,20是右值,所以输出12。{alert type="info"}贡献者的注释:这个示例演示了Scott Meyers建议使用std::forward进行转发引用,使用std::move进行右值引用的原则。{/alert}{/card-default}
2023年07月13日
1 阅读
0 评论
0 点赞
2023-07-13
[C++Quiz]#185、#207、#219
Question #219{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> template<typename T> T sum(T arg) { return arg; } template<typename T, typename ...Args> T sum(T arg, Args... args) { return arg + sum<T>(args...); } int main() { auto n1 = sum(0.5, 1, 0.5, 1); auto n2 = sum(1, 0.5, 1, 0.5); std::cout << n1 << n2; }{card-default label="答案及解析:" width=""}32这个很简单,n1,n2值即sum函数的返回值,这里有两个sum函数,最开始初始化时n1的第一个数据是double类型,所以实例化后就是 sum(double arg,...) ,返回值等于 0.5+sum(args...) ,执行嵌套语句,直到最后一个值匹配到 sum(T) ,我们可以看到所有数据的类型 T 其实都是由传入的第一个数据决定的,所以对于 n2 , int(0.5) 就是 0 啦所以输出32.{/card-default}Question #207{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> #include <map> using namespace std; int main() { map<int, int> m; cout << m[42]; }{card-default label="答案及解析:" width=""}0没什么好说的,秒了,map[42]不存在,对于这样的操作会 try_emplace 初始化为0。{/card-default}Question #185{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> template <typename T> void f() { static int stat = 0; std::cout << stat++; } int main() { f<int>(); f<int>(); f<const int>(); }{card-default label="答案及解析:" width=""}010模板对 f() 实例化时对类型为 int 和 const int 会实例化成不同的函数,所以他们有各自的 int stat,所以f(),f()调用的还是不同的函数。{/card-default}
2023年07月13日
0 阅读
0 评论
0 点赞
2023-07-12
[C++Quiz]#27、#41、#44
Question #41{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> int main() { std::cout << 1["ABC"]; }{card-default label="答案及解析:" width=""}B根据 标准 规定 1["ABC"] 就等同于 *(1+"ABC") 根据加法运算可以交换,所以就等同于 *("ABC"+1)即常见的"ABC"[1]。{/card-default}Question #27{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> struct A { virtual std::ostream &put(std::ostream &o) const { return o << 'A'; } }; struct B : A { virtual std::ostream &put(std::ostream &o) const { return o << 'B'; } }; std::ostream &operator<<(std::ostream &o, const A &a) { return a.put(o); } int main() { B b; std::cout << b; }{card-default label="答案及解析:" width=""}BB类型通过虚函数重写了A类型的 put 函数。对<<运算符进行了重载,重载之后对b进行<<操作会执行b的 put 函数输出“B”。{/card-default}Question #44{card-describe title="描述"}According to the C++17 standard, what is the output of this program?{/card-describe}#include <iostream> struct X { virtual void f() const { std::cout << "X"; } }; struct Y : public X { void f() const { std::cout << "Y"; } }; void print(const X &x) { x.f(); } int main() { X arr[1]; Y y1; arr[0] = y1; print(y1); print(arr[0]); }{card-default label="答案及解析:" width=""}YXarr[0] = y1的操作使 Y 类型的对象被转化成 X 类型,这个过程会丢掉对象的 Y 部分。这个过程一般称作 slicing (切片)。{/card-default}
2023年07月12日
0 阅读
0 评论
0 点赞
2023-07-08
C/C++选手初学Python可能遇到的问题
{card-describe title="描述"} 对于以C/C++入门的人(比如我)来说,刚上手Python并不是那么适应。比如我对Python的第一印象就是:“这玩意怎么长这样??” 我在这里对于CP之间的一些不同点做一个总结,如果有说的不对的地方欢迎指正!{/card-describe}列表:- 1.记得给变量初始化- 2.在需要的时候转换变量类型- 3.CP字符串 - 3.1字符访问(下标) - 3.2 substr()与[:] - 3.3其他1.记得给变量初始化 C++ 中每个变量都有指定的类型,类型决定了变量存储的大小和布局,C++的变量是不需要初始化的(编译器已经帮你完成了)。 Python中虽然也有基本类型,但是Python的变量只是变量,并不具有特定的类型,它是可以“随时根据需求转换的”,并且Python的变量需要初始化,也就是说,下面这行代码是错误的。a a = 1 print(a)在PyCharm运行之后结果如下:{alert type="error"}RunTimeError:Bad magic number in .pyc file{/alert} 所以在创建你的Python变量之前请记得给它初始化。2.在需要的时候转换变量类型 就像前文说的Python的变量并不具有特定的类型,也就是说即使你申明了一个整型变量,它也可能在后续的操作中变成其他类型的变量(感觉这样的说法对于py来说并不准确,但是对c++人来理解是这样的),下边就是一个例子:a = 2 a /= 2 print(a)运行结果:{message type="success" content="1.0"/} 可以看到我们本来申明为整型的变量在经过 “ /= ” 操作后变成了一个浮点型, 如果想保持整型就需要使用 “ //= ”。 一些操作是只有特定类型才能执行的,所以记得在需要的时候转化变量类型,你可以执行这样的操作:#此处省略...... a = int(a) #一样......3.CP字符串 C++中字符串可以由多种类型表示char[]、char*、string,在对其赋值时都是用 " " 双引号。 Python中单引号和双引号都是可以的,并且Python三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。就是说可以这样写:str = """ 生活不能等待别人来安排,要自己去争取和奋斗; 而不论其结果是喜是悲,但可以慰藉的是,你总不枉在这世界上活了一场。\n有了这样的认识,你就会珍重生活,而不会玩世不恭; 同时,也会给人自身注入一种强大的内在力量。 """ print(str)运行结果:{alert type="success"}生活不能等待别人来安排,要自己去争取和奋斗;而不论其结果是喜是悲,但可以慰藉的是,你总不枉在这世界上活了一场。有了这样的认识,你就会珍重生活,而不会玩世不恭;同时,也会给人自身注入一种强大的内在力量。{/alert}下边以C++的string对象进行类比3.1字符访问(下标) C++和Python都可以通过下标直接访问字符串中的单个字符,不同的是Python的[]用法并不单一,除了访问单个字符外还可以执行很多操作,这个后边再说。 Python的下标可以是负数,也就是说str[-1]是允许的,它代表字符串从尾到头的第一个元素,正数情况二者相同。3.2 substr()与[:] C++中药取得一个字符串的子串我们一般使用 substr() 函数 Python则可以直接用方括号加冒号[:]实现这样的操作 比如给定一字符串“Hello world”我们可以分别用两个语言进行如下操作:Python:str="Hello world" print(str[0:5])#从[0]截到[4] print(str[-11:-6])#从[-11]截到[-7] #只有头下标/尾下标的情况 print(str[:5])#尾下标是5,从[0]开始截取到[4] print(str[6:])#头下标是6,从[6]开始向后截取 ''' 注:[]中的头尾下标是左闭右开的[) '''运行结果:{message type="success" content="HelloHelloHelloworld"/}C++:#include <iostream> #include <string> using namespace std; int main() { string str = "Hello world"; cout << str.substr(0,5) << endl /*Hello*/ << str.substr(6,5); /*world*/ return 0; }3.3其他 除此之外两种语言的string对象都差不多:它们都有很多内置函数大大简化了C语言中的一些字符串算法;你可以对字符串进行+=的操作来连接两个字符串;不同的是Python的字符串可以进行 * 运算。 Python的输入一般用input(),这个函数默认的数据类型是string,所以还是第一条注意你需要的数据类型。你可以在CSDN上观看这篇文章: C/C++选手初学Python可能遇到的问题
2023年07月08日
0 阅读
0 评论
0 点赞
1
2
3