性能文章>【ModernCpp】新特性之CTAD>

【ModernCpp】新特性之CTAD原创

179900

你好,我是雨乐!

最近在阅读C++ Templates 2nd,发现有些很有意思的新特性,今天,借助本文,分享给大家。

从一个例子入手

首先,我们看如下例子:

template <typename T>
class Add{
 public:
  Add(T first, T second): first_{first}, second_{second} {}
  T result()const{return first + second;}
 private:
  T first_;
  T second_;
};

这个例子很简单,声明一个模板类Add,接收类型为T的构造函数Add,以及一个返回operator+结果的result()函数。

在c++17之前,如果我们要使用Add类,往往必须像如下这么做:

int main(){
  Add<int> ti(1,2);
  return 0;
}

即在实例化对象ot的时候必须指明类型int

自C++17起引入了新的特性Class Template Argument Deduction,简称为CTAD,即类模板参数推导,那么就可以像如下这样实例化ADD类:

int main(){
  Add ti(1,2);               //T 被推导为int
  Add td{1.2453.1415};     //T 被推导为double
  Add tf = {0.24f0.34f}; //T 被推到位float
  return 0;
}

用例

上面的例子,我们已经体会到了CTAD带来的好处(代码间接😁),下面结合在项目中的用的例子更进一步的来说明CTAD。

相比我们都知道std::lock_guard类,其主要用了实现RAII功能,尤其在多线程环境中用的最多,如下:

std::mutex m;
std::recursive_timed_mutex rm;

void fun1(){
    std::lock_guard<std::mutex> lg{m};
    //do sth
}

void fun2(){
    std::lock_guard<std::recursive_timed_mutex> lg{rm};
    //do sth
}

在C++17,我们往往得像上面这样写,即需要显式指定lock_guard的类型。但是,自C++17起,可以像如下这样写:

std::mutex m;
std::recursive_timed_mutex rm;

void fun1(){
    std::lock_guard lg{m};
    //do sth
}

void fun2(){
    std::lock_guard lg{rm};
    //do sth
}

显然,代码更加简洁统一。

限制

虽然CTAD用起来很方便,但是相对于不使用CTAD特性,有时候CTAD会存在一些问题,即编译器推导的类型并不是我们所预期的,仍然使用第一节中的例子:

int main() {
  Add ts("hello, ""world!\n");
  auto ret = ts.result();
  
  return 0;
}

在编译阶段,会报如下错误:

error: invalid operands of types 'const char* const' and 'const char* const' to binary 'operator+'
T result()const{return first_ + second_;}

即编译器会将"hello "和"world!\n"推导成为const char const,而c++的char是不支持operator+操作的,这就导致了上面的编译错误。

此时,我们可以使用C++17之前的实例方法即显示指明类型,如下:

int main() {
  Add<std::string> ts("hello, ""world!\n");
  auto ret = ts.result();
  
  return 0;
}

如果这样做的话,多少有点失去了CTAD的好处,为了解决这种类似的问题,C++17支持显示类型推导,即添加代码:

Add(const char*, const char*) -> Add<std::string>;

需要注意的是,这一行类型推导需要加在类声明之后,这样编译器在遇到参数为const cha*的时候,会自动将其推导为std::string.

这样,我们的例子最后如下:

Add(const char*, const char*) -> Add<std::string>;
int main() {
  Add ts("hello "" world!\n");
  ts.result();
}

以上~~

今天的文章就到这,我们下期见!

如果对本文有疑问可以加笔者微信直接交流,笔者也建了C/C++相关的技术群,有兴趣的可以联系笔者加群。

 

推荐阅读   点击标题可跳转

1、typedef vs using

2、lambda with template

3、性能优化利器之constexpr

 

点赞收藏
分类:标签:
高性能架构探索

公众号《高性能架构探索》

请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

初始化|这些年踩过的坑

初始化|这些年踩过的坑

0
0