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;
}

三.if switch初始化 使用迭代器操作时,可以使代码更紧凑
点击查看代码
// 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声明语句可以声明多个名称 样例:
点击查看代码
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;
}
2)[[nodiscard]] 所修饰的内容不可被忽略,主要用于修饰函数返回值 当用于描述函数的返回值时,如果调用函数的地方没有获取返回值 时,编译器会给予警告
点击查看代码
[[maybe_unused]] void func() //没有被使用的函数
{
cout << "test" << endl;
}
int main()
{
[[maybe_unused]] int num = 0; //没有被使用的变量
return 0;
}

九.charconv
是C++17新的标准库头文件,包含了相关类和两个转换函数。可以完成传统的整数/浮点和字符串互相转换的功能(atoi、itoa、atof,sprintf等),同时支持输出格式控制、整数基底设置并且将整
数和浮点类型对字符串的转换整合了起来。
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;
}
十.std::variant C++17中提供了std::variant类型,意为多变的,可变的类型。有点类似于加强版的union,里面可以存放复合数据类型,且操作元素更为方便。 variant提供了index成员函数,该函数返回一个索引,该索引用于表示 variant定义对象时模板参数的索引(起始索引为0),同时提供了一个函数 holds_alternative(v)用于查询对象v当前存储的值类型是否是T
点击查看代码
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 在编程中,经常遇到这样的情况:可能返回/传递/使用某种类型的对象。也 就是说,可以有某个类型的值,也可以没有任何值。因此,需要一种方法 来模拟类似指针的语义,在指针中,可以使用nullptr来表示没有值。

处理这个问题的方法是定义一个特定类型的对象,并用一个额外的布尔成
员/标志来表示值是否存在。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();//有值变没值
}
十二.std::any 在C++11中引入的auto自动推导类型变量大大方便了编程,但是 auto变量一旦声明,该变量类型不可再改变。 C++17中引入了std::any类型,该类型变量可以存储任何类型的值, 也可以时刻改变它的类型,类似于python中的变量。
点击查看代码
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

}
十三.std::apply 将tuple元组解包,并作为函数的传入参数
点击查看代码
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
}
十四.std::make_from_tuple 解包tuple作为构造函数参数构造对象
点击查看代码
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;
}

终于搞完了

posted @ 2025-04-23 00:22  北燃  阅读(8)  评论(0)    收藏  举报