C++20(C++ 编程语言标准2020版)将是C++ 语言一次非常重大的更新。C++20 核心语言有四大特征。
Concept(概念)
Concept其实已经不是什么新东西了,在 C++ 11 还是 0x 的年代就已经有Concept的的概念了,属于C++里面喊了无数次狼来了的东西,C++在经历了11/14/17,直到C++20才正式进入。
使用模板进行通用编程的关键思想是定义能通过各种类型使用的函数和类。但是在实例化模板时经常会出现用错模板类型的问题,其结果通常是几页难懂的报错信息。
template<typename T>
concept Integral = std::is_integral<T>::value;
Integral auto Add(Integral auto a,Integral auto b)
{
return a + b;
}
//Integral 这个concept需要 std::is_integral::value 中的类型参数 T。
//如果 std::is_integral::value 的值为 true,则没有问题。如果不为 true,则你会收到一个编译时间报错。
概念让你能为模板编写要求,而编译器则可以检查这个要求,概念革新了我们思考和编写通用代码的方式。原因如下:
- 模板是对模板类和函数的模板形参的约束,是接口的一部分;
- 类模板中的函数重载或特殊化可以基于概念进行;
- 编译器能够比较模板参数与实际的模板参数是否满足concept,所以能得到更好的报错信息。
当然,这还不是全部,篇幅原因后续再讲。
Ranges Library(范围库)
Ranges实际上可理解为一个Concept,它针对集合,提供begin()和end()两个方法,返回一个指示类(iterator),然后就可以枚举集合中的所有元素。Range概念的出现,感觉上把集合类(容器类)的概念更抽象化(学术化)了,ranges库中有许多Concept。它支持的算法满足以下条件:
- 可以直接在容器上操作;无需迭代器指定一个范围;
- 可以宽松地评估;
- 可以组合;
在STL使用上,大致有两个不方便,一是大量应用iterator,二是集合操作写法不直观。
看下面示例代码(views是一种Range),没有使用iterator,还让集合操作也变得极为简单了。
int main()
{
auto const data {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = data | std::views::remove_if([](int i) { return i % 2 == 0;}) );
}
// result = {1, 3, 5, 7, 9 };
int main()
{
auto const ints{0,1,2,3,4,5};
auto even=[](inti) //判断i是否偶数
{
return 0==i%2;
};
auto square=[](inti) //计算i的平方
{
return i*i;
};
for( int i : ints | std::views::filter(even) | std::views::transform(square) )
{
std::cout<<i<<' '; //输出:0 4 16
}
std::cout<<std::endl;
for (int i : std::views::transform(std::views::filter(ints, even), square))
{
std::cout << i <<' '; //输出:0 4 16
}
}
这代码行云流水,实在忍不住要夸赞一番!
Coroutines(协程)
协程是广义的函数,能在保持状态的同时暂停或继续。协程通常用来编写事件驱动型应用。事件驱动型应用可以是模拟、游戏、服务器、用户接口或算法。协程也通常被用于协作式多任务(cooperative multitasking)。
下方代码块,函数 getNext 是一个协程,因为它使用了关键字 co_yield。generator是一个模板类(具体实现颇为复杂,代码量也较大后续单讲);它有两个方法gen有一个无限的循环,其会在 co_yield 之后返回 value(协程暂停)。调用 next()会继续这个协程,接下来的 getValue 调用会获取这个值。在 gen 调用之后,这个协程再一次暂停,其暂停会一直持续到下一次调用 next()。
template <typename T>
class generator
{
}
generator<int> gen(int start=0,int step=1)
{
auto value=start;
for(int i=0; ;++i)
{
co_yield value; //返回value,协程暂停
value+=step;
}
}
int main()
{
std::cout<<std::endl;
std::cout<<"gen():";
auto gen=gen();
for(inti=0;i<=10;++i)
{
gen.next(); //协程继续
std::cout<<""<<gen.getValue();
}
}
Module(模块)
Module的优点
- 没有头文件
- 声明实现仍然可分离, 但非必要
- 可以显式指定哪些(类, 函数等)导出
- 不需要头文件重复引入宏 (include guards)
- 模块之间名称可以相同不会冲突
- 模块只处理一次, 编译更快 (头文件每次引入都需要处理)
- 预处理宏只在模块内有效
- 模块引入顺序无关紧要
创建模块cppcon,
// cppcon.cpp
export module cppcon;
namespace CppCon
{
auto GetWelcomeHelper() { return "Welcome to CppCon"; }
export auto GetWelcome() { return GetWelcomeHelper();} //显示指定GetWelcome导出
}
引用模块cppcon
// main.cpp
import cppcon;
int main()
{
std::cout << CppCon::GetWelcome();
}
C++20的四大新特性内容其实还挺多的,本文旨在介绍四大特性说的是个什么事,感兴趣的朋友记得点关注,我会继续做更详细的讲解。