【ModernCpp】新特性之CTAD原创
你好,我是雨乐!
最近在阅读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.245, 3.1415}; //T 被推导为double
Add tf = {0.24f, 0.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++相关的技术群,有兴趣的可以联系笔者加群。