class template argument deduction for everyone
26 Apr 2019
|
|
演讲人是Stephan T. Lavavej ,负责msvc stl的
这个演讲的主题就是Class template argument deduction,简称CTAD,之前也接触过。借这个ppt彻底顺一下
简而言之这个c++17新特性给了类模板像函数模板一样的推导能力,可以省去指定参数,让编译器帮你推导
std::vector v{2}; //推导成vector<size_t>
lock_guard l(mtx); //推导成lock_guard<mutex>
还有pair,tuple 以及智能指针,以及guard,从此make_函数基本可以下岗
对比函数模板的推导,为什么类模板之前没有推导,以pair举例
- 可能推导的类型很多
- pair<int, int> p(11,22); 如果不指定int,有可能是long,类型很多
- 解决办法,make_pair,通过函数模板转发和退化forwarding and decay
- 缺点,低效,是个函数调用,调试烦人,且很繁琐(其实还行吧,多打个make_)
基本语法 初始化(){},直接初始化和赋值初始化
应用的场景
-
容器,包括pair和tuple
-
容器的范围初始化
list<pair<int, string>> lst; ...;//添加元素等等 vector v(lst.begin(),lst.end());
-
-
lock_guard
-
functor 比如sort中的greater<\void>{}
遇到的错误以及引起的原因
pair p{};// 无法推导类型,不像上面的greater, 没有默认参数
array arr = {1,2,3.14};//推导不出个数
shared_ptr sp(new string);//由于数组指针的退化,这个指针类型区分不出是数组指针还是普通指针,shared_ptr<string> shared_ptr<string []>
上面的例子也引入了,缺少信息和歧义的推导条件会错误,这和函数模板类似
- P1021提案 设计的场景可以fix
- 别名模板,显式模板参数这两个场景无法使用CTAD
- 需要推导指引,比如array,继承构造函数
推导指引
比如字符串,类型很容易推导成char[N] ,如果想要string,就需要写推导指引规则
能构造不等于能推导
template <typename A, typename B>
struct Peppermint{
explicit Peppermint(const A&){}
};
Peppermint<int, double> p1{11};
Peppermint p2{22};//err
第二种情况缺少了参数,也没有提示参数,推导不出来
再比如指针
template <typename A, typename B>
struct jazz{
jazz(A*, B*){}
};
int i = 1;
const double d = 3.14;
jazz j1{&i, &d};
jazz j2{&i, nullptr};//err
- CTAD自动推导原则:模板参数构造中都带上了,或者有默认的
- 不能自动推导的原因
- 模板参数没带上
- 提供的参数没有帮助推导的额外信息 nullptr
- 参数不可推导 list<T>::iterator
一个推导规则
template <typename T>
struct MyVec{
template <typename It> MyVec(It,It){}
};
template <typename it> MyVec(It,It) -> MyVec<typename iterator_traits<It>::value_type>;//建立关系
int *ptr = nullptr;
MyVec v(ptr,ptr);
- 如果是转发构造呢,CTAD是支持的,而make_函数有退化
值退化
reference
- https://zh.cppreference.com/w/cpp/language/class_template_argument_deduction
- 之前也提到过这个东西https://wanghenshui.github.io/2018/08/17/overload-trick
- ppt地址 https://github.com/CppCon/CppCon2018/tree/master/Presentations/class_template_argument_deduction_for_everyone
contact
。