现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34196 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

28 | Concepts:如何对模板进行约束?

你好,我是吴咏炜。
从这一讲开始,我们进入了未来篇,展望一下即将在 C++20 出现的新功能。我们第一个要讨论的,是 concepts(概念)——一个难产了很多年才终于进入 C++ 的新功能。

一个小例子

老规矩,要讲“概念”,我们先看例子。
我们知道 C++ 里有重载,可以根据参数的类型来选择合适的函数。比如,我们可以定义 half 对于 intstring 有不同的作用:
int half(int n)
{
return n / 2;
}
string half(string s)
{
s.resize(s.size() / 2);
return s;
}
初看,似乎重载可以解决问题,但细想,不对啊:除了 int,我们还有差不多的 shortlong 等类型,甚至还有 boost::multiprecision::cpp_int;除了 string,我们也还有 wstringu16stringu32string 等等。上面的每个函数,实际上都适用于一族类型,而不是单个类型。重载在这方面并帮不了什么忙。
也许你现在已经反应过来了,我们有 SFINAE 啊!回答部分正确。可是,你告诉我你有没有想到一种很简单的方式能让 SFINAE 对整数类型可以工作?Type traits?嗯嗯,总是可以解决的是吧,但这会不会是一条把初学者劝退的道路呢?……
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

C++20 新功能:Concepts(概念)是一项引人注目的技术革新。Concepts是一组对模板参数的约束条件,旨在解决模板接口设计不满意的问题。文章介绍了Concepts的基本概念和历史发展,包括Bjarne Stroustrup多次尝试将其引入C++标准化的过程,以及Concepts Lite的重新启动和最终进入C++20标准的过程。通过一个例子展示了如何使用Concepts对模板进行约束,从而简化代码并提高可读性。此外,文章还介绍了部分标准概念的定义和测试结果,展示了Concepts在实际代码中的应用。总体而言,Concepts作为C++20的重要功能增强,为C++语言带来了重要的技术进步。概念可以用来对模板参数进行约束,能取代SFINAE,产生更好、更可读的代码。文章还展示了Concepts在实际代码中的应用,以及在出错信息上的优势。总的来说,Concepts作为C++20的重要功能增强,为C++语言带来了重要的技术进步。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(7)

  • 最新
  • 精选
  • 李云龙
    老师,您的这段代码,OutContainer是需要2个模板参数的,但是特化的时候只提供了一个类型作为模板参数,是不是漏写了一个模板参数?我回到13讲,是不是应该加上 allocator<decay_t<decltype(f(*begin(inputs)))>>>?还是编译期会帮我们自动推断第二个类型? template < template <typename, typename> class OutContainer = vector, typename F, class R> auto fmap(F&& f, R&& inputs) -> decltype( begin(inputs), end(inputs), OutContainer<decay_t< decltype(f(*begin( inputs)))>>());

    作者回复: 是错了。谢谢。正文已更新。

    2023-11-05归属地:北京
    1
  • Geek_QiDian
    请问老师的 output_container 的概念实现版本有吗?想研究一下

    作者回复: 有支持 ranges 的版本 output_range(URL 里相应改一下就行),没有去做概念实现版本过。

    2021-08-08
    1
  • 廖熊猫
    c++里的泛型约束和java或者c#中的泛型约束很像,但是复杂了好多...不像后者只能约束泛型参数实现某一接口,c++可以通过很小的约束组合成需要的约束,感觉这就是函数式里面经常提的组合的力量吧

    作者回复: Java和C#的泛型约束都太弱了,只能是你需要做什么,而不能说你不可以做什么。另外,这种基于继承的约束是 跟 C++ 的鸭子类型方式背道而驰的:概念仍然是基于鸭子类型的,虽然是更形式化的鸭子类型——但它仍然是不使用继承体系的。

    2020-02-10
    1
  • 易轻尘
    个人认为好处就是1. 代码量减少,2. 代码变得更加易读,和老师说的3. 出错信息变得更友善了。 我对模板编程不是很熟练,所以之前很少通过SFINAE来直接规制函数的模板参数类型,反而是通过模仿java的做法,写模板类作为接口,包装实际的类型。如果需要的约束简单这样写也不麻烦,但是无法像concepts的写法那样随意的组合各种约束,要实现这节图中那种类似树状的结构麻烦得就不是一点半点了。 至于缺点,暂时没有想到,希望老师能提示提示

    作者回复: 有答案的。学到这么后面了,就去看一下答案吧。

    2020-06-22
  • 范闲
    如果是引入概念的话 1.从当前的标准库里可以抽取更多近似概念的操作(类似于itrerator),直接调用即可。 2.在class的设计上直接标记概念相关关键字就可以检查class的设计是不是符合原则 缺点:理解起来比较困难

    作者回复: 对于思维严谨的人来说,是抽象,是好事,不是困难。

    2020-04-07
  • 李亮亮
    vs2019 c++17 template <typename, typename> class OutContainer = vector, 这里提示错误: C2065 “vector”: 未声明的标识符

    作者回复: 代码前面要有: #include <vector> using namespace std;

    2020-03-05
    2
  • 始之源稳于心
    吴老师,你好,我问一个与此文章无关的,一个GDB调试的问题: 一个网络多线程服务,一个socket一个线程。有一个共享变量用boost的unordered_map,同步也用boost的unique_lock 程序在运行时基本正常,但在gdb调试时只要打印共享变量(即使里面没有数据),就会收到SIGSEG,调试其它变量或用下面的步骤就没事 1 handle SIGPIPE nostop noprint 2 set print elements 0 3 将共享的变量的类型变为 stl的map 问题: 这种情况产生的主要原因是什么,用了boost的 hash map吗,和屏蔽管道关系有多大?

    作者回复: 没遇到类似问题,不熟悉。建议到 Stack Overflow 上去问,最好描述清楚环境,并且有一个最小的测试程序。 一般而言,网络程序和多线程程序要做好单元测试,也只有单元测试可以在调试器里顺利进行。完整系统的调试多靠记日志和分析。

    2020-02-05
    2
收起评论
显示
设置
留言
7
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部