一、concepts的入门应用

concepts的应用是一个非常必要的问题。它对于模板在实际编程中的友好性有着至关重要的作用。先从最简单的一个示例说起:

 struct PlusSum{int d_ = 9;double a_ = 11;};template <typename T,typename N>concept C2 = requires(T t, N n) {{t + n}-> std::same_as<T>;//要求t+n是T类型};template <typename T, typename N>concept C1 = requires(T t, N n) {{t + n}-> std::convertible_to<T>;//要求t+n可转成T类型};template<typename T,typename N>T Sum(T t, N n) requires C2<T,N>{return t + n;}int main()
{int d = 10;double a = 9;//在这种情况double+int=>double所以C2不满足int r = Sum(d ,a);std::cout << "sum value:" << r << std::endl;//无法满足约束r = Sum(PlusSum{}, PlusSum{});std::cout << "sum value :" << r << std::endl;
}

如果在这个函数里把概念部分先去除,编译器只会报“未匹配的重载函数”。如果把C1打开,则会报约束无法满足,但此时只是第个Sum有问题,第一个没有问题。如果再把C2打开,把C1注释,会发现两个Sum都说不满足约束。换句话说,两个约束一个比一个更严格,所以在某些场景下,对类型要求严格时,可以做类似的判断。
在这样一个简单的例程中,当然显示不出来约束的巨大优势。毕竟就几行代码,一扫而过也能找到错误。但是如果在实际工程中,不断嵌套调用,如何一下子定位出来呢?甚至像那些非严格自动转化的类型引起的警告导致的错误,可能会让开发者寻找一天。这时候儿用约束的优势就明白的显现出来了。

二、更进一步的应用

在上面只是简单的使用了一下requires,下面综合的对一些成员函数,CV限定等进行控制,看一下代码:

//函数限制template<typename T>concept func_ask = requires(T t){t.must();};class A {};class B{public:void must() const {}};class C : public A{public:void must(const std::string& s = "test") const { std::cout << s << std::endl; }};//下面的继承改成私有亦会报错class D :public B//private B{public:D() {};~D() {};private:};template <typename T>concept is_const_ok = !std::is_const_v<T>;template <typename T>concept is_size_ok = requires (T t)//有size()函数且返回值可转size_t{{t.size()}->std::convertible_to<std::size_t>;};template<typename T,typename N>concept cs1 = requires (T t,N n){{t.Get(n)}->std::same_as<std::string>;};template <typename T>class OkTest{public:/*int*/std::string Get(int d) { std::cout << "is test" << std::endl; return ""; }//返回值限制,可以试一下};
//带参数限制template <typename T,typename N> requires cs1<T,N>void TestOK(T t,N n){t.Get(n);}template<typename T>concept cs = requires (T t){// {t}->std::same_as<std::string>;//约束通不过,估计是引用常量啥的问题{std::decay_t<T>(t)}-> std::same_as<std::string>;//requires requires {std::is_same_v<decltype(t), decltype("123")>; };//这个约束也可以,不过有点LOW//t.size() < 6;//这个约束没有用,可以考虑一下为什么};template <typename T>concept cf = requires (T t){std::is_function_v<decltype(t) >; };template <cs T>auto DataGet( T &t){return t;}template<typename T, cf F >class MyConceptsExample{public:MyConceptsExample() {}~MyConceptsExample() {}template <cs U> U SetName(U t){s_ = t;std::cout << "get name is:" << s_ << std::endl;return s_;}int size() {return 10;}std::string s_ = "";F f_;};template<func_ask T>requires is_const_ok<T>  //简化了std::enable_if的应用,引用永远是flase=>truevoid must(const T& t){t.must();}template<typename T>requires is_size_ok<T>auto createEx(T& t){std::cout << "size value is:" << t.size() << std::endl;}
#include<functional>typedef void(*PF)(int);void IsFunc(int d){std::cout << d << std::endl;}void  TestMyConcepts(){OkTest<int > ok;TestOK(ok,10);std::string s = "123";int d = 0;DataGet(s);//换成d,就会报约束问题MyConceptsExample<int, std::function<void(int)>> my;MyConceptsExample<int, PF> my1;// my.SetName(s);createEx(my);//must(A()); // 未满足关联约束must(B());must(C());must(D());return;}int main()
{TestMyConcepts();return 0;
}

基本按上面的代码,就可以把需要概念应用上来。这样,在实际开发中,对一些细节的掌控就可以通过概念来控制。比起以前的SFINAE要简单方便易理解多了。特别是在c++20中好多原来SFINAE中的技巧都可以直接使用了,所以说技术还是得进步,光靠技术人员玩一些花活,不是发展之道。解决一时之需还可,长久来看,反而对c++语言的发展有碍。

三、更高的一些用法

分析完了一些基本的用法,来看一些高级的用法。
1、模板的特化
在模板的使用中,使用了concepts后,模板的特化和偏特化不受影响,但在此过程中必须符合约束的要求:

#include <concepts>
#include <string>
#include <type_traits>template <std::signed_integral T>
class NewData
{
public:T GetData(T t) { return t; }
};
template <>
class NewData<long> {};
//template <>
//class NewData<std::string> {};//不满足约束template <std::signed_integral T,typename U>
requires std::is_const_v<U>
class NewDataConst
{
public:T GetData(T t,U u) { return t; }};
template<typename U>
class  NewDataConst<int, U> {};
template<typename U>
class  NewDataConst<double, U> {};
template<typename T>
class  NewDataConst<T,const  int> {};
template<typename T>
class  NewDataConst<T, const std::string> {};int main(){NewData<int> nd;//NewData <float> nd1;//不满足约束//NewData <std::string> nd2;//不满足约束NewData<long> nd3;// NewDataConst<double, int> ndc;NewDataConst<int, const double> ndcc;//double换成 std::string会有歧义// NewDataConst<int, int> n;return 0;}

上面的代码会发现,全特化时约束立刻起作用,而偏特化要等到定义应用时才会起作用。当然concepts在一些情况下也可以特化模板:

 template <typename T>class Example {public:Example() { std::cout << "stand " << std::endl; }};template <std::integral T>class Example<T> {public:Example()  { std::cout << "no stand " << std::endl; } };void TestExample() {Example<int> t1; // no standExample<std::string> t2; //  stand}int main()
{TestExample();return 0 ;
}

2、函数重载
那么如果有concepts的限制,函数重载有什么影响么?

 void funcall(int d){std::cout << "call stand func" << std::endl;}template<typename T>void funcall(T t){std::cout << "call template func" << std::endl;}template<std::integral T>void funcall(T t){std::cout << "call concept template func" << std::endl;}template <>void funcall<double>(double d){std::cout << "call all template func" << std::endl;}
int main()
{int d = 0;funcall(d);funcall("test");funcall<>(1.1);funcall<int>(1);return 0;
}

结果:

call stand func
call template func
call all template func
call concept template func

通过上面的代码可以看到其实concepts是不影响函数重载的。

四、总结

古人形容朝代的兴亡用“其成也勃焉,其亡也忽焉”。其实,一个语言的兴衰也是如此。js 和python为什么能够迅速起来,简单是第一位。不要提什么功能强大,那都是基于简单的前提。所以c++必须得走一条在尽可能范围的情况下,把编写c++代码的难度降下来。这个不是谁说了算的问题,是涉及到一个语言能否存在的重要前提。
让我们拭目以待c++23以后的新标准会有什么更大惊喜出来。

跟我学c++中级篇——concepts的几个应用相关推荐

  1. 跟我学c++中级篇——类型擦除

    一.类型擦除 很多人一直都认为,类型擦除是一些高级语言(如Java)才具有的,其实在c++中也可以实现类型擦除.那么什么是类型擦除呢?我们都知道,C/c++是一门强类型语言,也就是说,编译器必须知道数 ...

  2. 跟我学c++中级篇——STL字符串之std::string_view

    一.标准库字符串处理 C和C++的一个很不一样的区别就是对字符串的处理,在c++的标准库里提供了一个std::string的字符串操作类.这使得c++对字符串的操作从某种程度上摆脱了原始指针的操作.从 ...

  3. 『中级篇』docker导学(一)

    原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』docker导学(一) 这两年容器技术及其相关工具,平台异常火爆.在各大技术论坛或云计算峰会议题中,都会占很大比重, ...

  4. 『中级篇』docker容器安装wordpress(37)

    原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』docker容器安装wordpress(37) 第一节的时候我就部署过wordpress,可能很多老铁一头雾水不知道 ...

  5. Android中级篇之百度地图SDK v3.5.0-一步一步带你仿各大主流APP地图定位移动选址功能

    from: http://blog.csdn.net/y1scp/article/details/49095729 定位+移动选址 百学须先立志-学前须知: 我们经常在各大主流APP上要求被写上地址, ...

  6. Java工程师学习指南 中级篇

    Java工程师学习指南 中级篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我写的文章都是站 ...

  7. 『中级篇』什么是Container(15)

    原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』什么是Container(15) 镜像(Image),跟你装操作系统的iso镜像一个概念.容器(Container) ...

  8. 『中级篇』docker-swarm创建一个多节点集群(43)

    原创文章,欢迎转载.转载请注明:转载自IT人故事会,谢谢! 原文链接地址:『中级篇』docker-swarm创建一个多节点集群(43) docker Swarm是Docker官方提供的一款集群管理工具 ...

  9. 运维“打怪”晋级之路之中级篇

    中级篇 有些人认为,其实运维就是部署某个软件,设置些基础功能,就算会运维了. 举个例子:安装LAMP,LNMP,就感觉部署方法我都掌握了.其实网上大多数都有一键安装脚本啥的根本没有啥技术含量,在面试官 ...

最新文章

  1. 【蓝桥杯】子串分值---笔记
  2. 云原生时代 RocketMQ 运维管控的利器 - RocketMQ Operator
  3. linux shell 中21含义
  4. HDU 4701 Game
  5. oppo专用计算机,OPPO手机助手
  6. 玩转springboot2.x 通过druid-spring-boot-starter整合Druid(Mybatis版)
  7. 软件系统安全测试和性能测试的区别,【安全测试】性能测试进阶——基本概念篇...
  8. Starling GodRay 效果实现
  9. MyBatis的动态SQL详解nbsp;(转载)
  10. Optisystem 光锁相环
  11. 分子量-算法竞赛习题3-2:给出一种物质的分子式(不带括号),求分子量。本题中的分子式只包含4种原子,分别为C, H, O, N,原子量分别为12.01, 1.008, 16.00, 14.01。
  12. seige压力测试用法
  13. 数据驱动测试(DDT)入门
  14. 什么计算机网络成瘾,计算机网络与网络成瘾.pdf
  15. 2021-03-17 RK3288 接PHILIPS 4K显示器HDMI开机概率性不显示的问题
  16. 家装产业的数字化,正在成为越来越多人的新共识
  17. 历年评书出版一览表(1955~1994)
  18. 语音对讲功能在车载监控系统中的应用意义
  19. android 8三星note8,去年发布的三星Note8到底还值不值得买,三星Note8深度体验!!!...
  20. lnoi2019游记

热门文章

  1. poj Best Cow Line
  2. 使用 FFmpeg(bilibili视频m4s合成mp4)
  3. RHEL4-ASU2-i386上安装oracle9204
  4. mysql服务端heidisql_MySQL管理工具HeidiSQL
  5. DOM定义 DOM对象
  6. 再谈FEC与UDP可靠传输,音视频FEC 应用
  7. 苏州整车环境试验仓试验
  8. 使用moment计算两个日期的相差天数
  9. Android 应用清单简介1
  10. 【工作记录】网易云信最近联系人中加入本地服务端数据