C++ 基础 day3 C++17新特性
4.22
夜深该睡了明天更(
一.inline变量
扩展的inline用法,使得可以在头文件或者类内初始化静态成员变量
案例:
点击查看代码
// mycode.h
inline int value = 100;
// mycode.cpp
class AAA {
inline static int value2 = 200;
};
二.结构化绑定
1)在C++11中,如果需要获取tuple中元素,需要使用get<>()函数或者tie<>函数,这个函数可以把tuple中的元素值
转换为可以绑定到tie<>()左值的集合,也就是说需要已分配好的内存去接收;用起来不方便。
点击查看代码
int main() {
auto student = make_tuple(string{ "Zhangsan" }, 19, string{ "man" });
string name;
size_t age;
string gender;
tie(name, age, gender) = student;
cout << name << ", " << age << ", " << gender << endl;
// Zhangsan, 19, man
return 0;//C++
}
2)C++17中的结构化绑定,大大方便了类似操作,而且使用引用捕获
时,还可以修改捕获对象里面的值,代码也会简洁很多
点击查看代码
int main() {
auto student = make_tuple(string{ "Zhangsan" }, 19, string{ "man" });
auto [name, age, gender] = student;
cout << name << "," << age << "," << gender << endl;
return 0;
}
点击查看代码
// C++11
unordered_map<string, int> stu1{ {"zhangsan", 18},{"wangwu",19} };
auto iter = stu1.find("wangwu");
if (iter != stu1.end()) {
cout << iter->second << endl;
}
// C++17
if (auto iter = stu1.find("wangwu"); iter != stu1.end()) {
cout << iter->second << endl;
}
四.简化的嵌套命名空间
样例:
点击查看代码
// C++17之前
namespace A {
namespace B {
namespace C {
void func1() {}
} // namespace C
} // namespace B
} // namespace A
// C++17
namespace A::B::C {
void func1() {}
} // namespace A::B::
点击查看代码
using std::cout, std::cin
五.lambda表达式捕获 this
一般情况下,lambda表达式访问类成员变量时需要捕获this指针,
这个this指针指向原对象,即相当于一个引用,在多线程情况下,
有可能lambda的生命周期超过了对象的生命周期,此时,对成员变
量的访问是未定义的。(没学过多线程,悲
因此C++17中增加捕获this,此时捕获的是对象的副本,也可以理
解为只能对原对象进行读操作,没有写权限。
点击查看代码
#include <iostream>
using namespace std;
class ClassTest {
public:
int num;
void func1() {
auto lamfunc = [*this]() { cout << num << endl; };
lamfunc();
}
};
int main() {
ClassTest a;
a.num = 100;
a.func1();
return 0;
}
点击查看代码
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f(); // 声明 f 带四个属性
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 同上,但使用含有四个属性的单个属性说明符
// C++17:
[[using gnu:const, always_inline, hot]] [[nodiscard]]
int f [[gnu::always_inline]] (); // 属性可出现于多个说明符中
int f() {return 0;}
七._has_include
跨平台项目需要考虑不同平台编译器的实现,使用__has_include可以判断
当前环境下是否存在某个头文件。
点击查看代码
int main() {
#if __has_include("iostream")
cout << "iostream exist." << endl;
#endif
#if __has_include(<cmath>)
cout << "<cmath> exist." << endl;
#endif
return 0;
}
八.新增属性
1)[[fallthrough]]
switch语句中跳到下一条语句,不需要break,让编译器忽略告警。
点击查看代码
int i = 1;
int result;
switch (i) {
case 0:
result = 1; // warning
case 1:
result = 2;
[[fallthrough]]; // no warning
default:
result = 0;
break;
}
点击查看代码
[[maybe_unused]] void func() //没有被使用的函数
{
cout << "test" << endl;
}
int main()
{
[[maybe_unused]] int num = 0; //没有被使用的变量
return 0;
}
九.charconv
数和浮点类型对字符串的转换整合了起来。
1)chars_format//字符串转换
点击查看代码
/*from_chars
struct from_chars_result {
const char* ptr;
std::errc ec;
};*/
void test1() {
string s1{ "123456789" };
int val = 0;
auto res = from_chars(s1.data(), s1.data() + 4, val);
if (res.ec == errc()) {
cout << "val:" << val << ",distance:" << res.ptr - s1.data() << endl;//转换成功
}
else if (res.ec == errc::invalid_argument) {
cout << "invalid" << endl;//转换失败
}
s1 = string{ "12.34" };
double value = 0;
auto format = chars_format::general;
res = from_chars(s1.data(), s1.data() + s1.size(), value, format);
cout << "value:" << value << endl;
//value:12.34
s1 = string{ "xxxxxxxx" };
int v = 1234;
auto result = to_chars(s1.data(), s1.data() + s1.size(), v);//数字转字符串
cout << "str:" << s1 << ",filled:" << result.ptr - s1.data() << "characters." << endl;
//s1:1234xxxx,filled:4 characters.
return;
}
点击查看代码
void test2() {
variant<int, double, string> d;//加强版union
cout << d.index() << endl;//0
d = 3.14;
cout << d.index() << endl;//1
d = "hi";
cout << d.index() << endl;//2
cout << holds_alternative<int>(d) << endl;//0
cout << holds_alternative<double>(d) << endl;//0
cout << holds_alternative<string>(d) << endl;//1
return;
}
处理这个问题的方法是定义一个特定类型的对象,并用一个额外的布尔成
员/标志来表示值是否存在。std::optional<>以一种类型安全的方式提了这样的对象。
点击查看代码
void test3() {
std::optional<int> o1 = 30;
std::optional<int> o2;
std::optional<int> o3 = 10;
std::optional<int> o4 = o3;
if (o1) {
printf("o1 has value\n");
}
if (o1.has_value()) {
printf("o1 has value\n");
}
cout << *o1 << endl;//访问
std::optional<string> o5 = "orange";
cout << o5->c_str() << endl;
cout << o5.value()<< endl;
o1.reset();//有值变没值
}
点击查看代码
void test4() {
cout << boolalpha;
any a;
cout << a.has_value() << endl;//false
cout << a.type().name() << endl;//false
any b = 1;
auto c = make_any<float>(5.0f);
any d(6.0);
cout << b.has_value() << endl;//true
cout << b.type().name() << endl;//int
cout << c.has_value() << endl;//true
cout << c.type().name() << endl;//float
cout << d.has_value() << endl;//true
cout << d.type().name() << endl;//double
}
点击查看代码
int add(int a, int b) {
return a + b;
}
void test7() {
auto add_lambda = [](auto a, auto b, auto c) {
return a + b + c;
};
cout << apply(add, pair(2, 3)) << endl;//结构化解绑,5
cout << apply(add_lambda, tuple(2, 3, 4));//9
}
点击查看代码
class ClassTest {
public:
string _name;
size_t _age;
ClassTest(string name, size_t age) :_name(name), _age(age) {
cout << "name:" << _name << ",age:" << _age << endl;
}
};
void test6() {
auto param = make_tuple("zhangsan", 19);
make_from_tuple<ClassTest>(move(param));//解包tuple作为构造函数参数构造对象
return;
}
十五.std::string_view
在C++17中,增加了std::string_view类型,它通过char字符串构造,
但是并不会去申请内存重新创建一份该字符串对象,只是char字
符串的一个视图,优化了不必要的内存操作。相应地,对源字符串
只有读权限,没有写权限。
点击查看代码
void func1(string_view str_v) {
cout << str_v << endl;
return;
}
void test8() {
const char* charStr = "hello world";
string str{ charStr };
string_view str_v(charStr, strlen(charStr));//当char*转化成string,不用申请额外的内存,只读
cout << "str:" << str << endl;
cout << "str_v:" << str_v << endl;
func1(str_v);
}
十六.std::as_const
将左值转化为const类型
点击查看代码
void test9() {
string str = { "C++ as const test" };
cout << is_const<decltype(str)>::value << endl;//查询是否为const变量
const string str_const = as_const(str);
cout << is_const<decltype(str_const)>::value << endl;
}
终于搞完了