下午好,亲爱的读者!
本文是我阅读Scott Meyers的《 Effective and Modern c ++》一书时所写的一系列抽象文章中的第一篇。 在github.com上专门建立的项目中,每一篇文章都将有一个单独的目录, 并带有使用所描述功能和技术的示例。
模板类型推断
成功的设计是当消费者不知道设备如何工作,但一切都适合他时。
例如,模板类型的结论是存在模板函数时调用的,而没有任何模板和尖括号。 同时,编译器猜测在函数的特定对象中将需要使用哪种类型。
Meyers将显示的类型“ T”和由程序员在参数定义中指定的类型“ ParamType”进行划分。
1.参数视图-链接或指针
为了快速了解派生规则,我将以模板的形式反映出来:
输入类型 -> 类型,参数 -> 输出类型 [, 参数的最终类型 ]
带有链接的示例:
template<typename T> // T void func(T& param) // - T& int x = 0; // int func(x);
派生类型T时 ,参照性(*,&)被丢弃,因为在定义函数时已经指出了参照性(*,&),就好像它意味着“您在此处传递任何内容,我们将假定这不是链接,因为参照性已经在使用位置添加了-在我们的函数f“
按照相同的原理,如果在功能参数中指定了恒定性,则将其丢弃。 在链接,指针,不变性上,都施加了专有掩码。
提款计划
// int —> (T & param) —> int; const int —> (T & param) —> const int; const int & —> (T & param) —> const int // int —> (const T & param) —> int; const int —> (const T & param) —> int; const int & —> (const T & param) —> int; // int * —> (T * param) —> int; const int —> (T * param) —> const int; const int * —> (T * param) —> const int; // int * —> (const T * param) —> int; const int —> (const T * param) —> int; const int * —> (const T * param) —> int;
2.论点类型-通用参考
斯科特提到,稍后将考虑通用链接,因此只需很少考虑就可以记住他在此处分为rvalue和lvalue的参数规则。
template<typename T> void func(const T&& param)
左值的推理规则
斯科特声称,这是将T作为参考输出的唯一情况。
在以下示例中,函数描述中的参数类型为通用左值引用 。 可以看出,T是显示为链接还是恒定链接,具体取决于
从输入参数来看,在这种情况下,param参数本身的类型也是一个引用。
lvalue int —> (T &¶m) —> int &, param - int& lvalue const int —> (T &¶m) —> const int &, param - const int& lvalue const int & —> (T &¶m) —> const int &, param - const int&
参数本身的类型也将被替换。 我认为这是由于该语言无法考虑左值变量分配的事实,该左值变量位于可以进一步移动的值之上。 稍后我们将找到通用链接,我们将对其进行解决。
为了验证T是否确实是类型引用,我在模板函数的主体中编写了T myVar ,该T同时显示并预期收到一条消息- “声明为引用但未初始化” -链接:)
右值的推理规则
第1款的“正常”规则适用。
rvalue int —> (T &¶m) —> int, param - int&&
已经很明显,仅对于右值临时对象才“包括”通用引用,在其他情况下,当参数不是通用引用时,不会区分右值,左值
3.按值传递(原样)
当通过值传递时,原始参数的恒定性和引用性由于不必要的原因而被丢弃,因为它们是全新的独立对象,为什么它们需要与它们无关的限定符?
int —> (T param) —> int const int —> (T param) —> int const int & —> (T param) —> int
我想其他疯狂和不合逻辑的组合都会导致编译错误,事实证明,编译器的工作几乎总是可以理解的,您只需要听一遍这些解释即可。