跟我学c++中级篇——concepts的几个应用

一、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=>true
 void 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 stand
     Example<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以后的新标准会有什么更大惊喜出来。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一关于地名消歧的最新外文综述文献: Title: A survey of geographic information retrieval: approaches, models and technologies Authors: Xiaobin Liu, An Liu, Xiaoli Xie, Guoqing Zhou Journal: Journal of Geographical Sciences Year: 2019 Abstract: Geographic information retrieval (GIR) is an important task in the field of geographic information science, which aims to retrieve relevant geographic information from large-scale spatial databases. One of the key challenges in GIR is to disambiguate geographic names, which refers to the process of identifying the correct meaning of a geographic name in a specific context. This paper provides a comprehensive survey of the approaches, models, and technologies for geographic name disambiguation. The authors first introduce the basic concepts and challenges of GIR, and then review the existing methods for geographic name disambiguation, including rule-based methods, statistics-based methods, machine learning-based methods, and hybrid methods. They also discuss the existing evaluation metrics and datasets for evaluating the performance of geographic name disambiguation methods. Finally, the authors provide a summary of the current research trends and future directions in the field of GIR, highlighting the importance of developing effective and efficient methods for geographic name disambiguation. Keywords: Geographic information retrieval, geographic name disambiguation, rule-based methods, statistics-based methods, machine learning-based methods, evaluation metrics, research trends, future directions. Overall, this paper provides a comprehensive overview of the current state-of-the-art in geographic name disambiguation, and highlights the need for further research and development in this important area of geographic information science.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值