栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

《Effective Modern C++》学习笔记 - Item 33: 对auto&&参数使用decltype以转发它们

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《Effective Modern C++》学习笔记 - Item 33: 对auto&&参数使用decltype以转发它们

C++14 为我们带来了泛型 lambda(generic lambda),可以在参数声明中使用 auto。这个特性的实现原理也不难想到:将 lambda 生成类的 operator() 变为一个模板函数即可。例如,下面的 lambda 函数在编译中产生的类可能形如:

auto f = [](auto x){ return func(normalize(x)); };
↓
class SomeCompilerGeneratedClassName {
public:
	template 		// see Item 3 for
	auto operator()(T x) const 	// auto return type
	{ return func(normalize(x)); }
	
	... // other closure class functionality
};

如果 normalize 函数对左值和右值的处理方式不同,那么以上的写法就是欠妥的,因为不管外部调用 f 时的入参是左值还是右值,以 x 调用 normalize 调用的永远是左值版本(见 Item 23),这正是我们为什么需要用 std::forward 进行完美转发。

但这里有一个问题:std::forward 的调用形式是 std::forward(param),它需要借助 T 的信息区分左值和右值;然而不像模板函数,lambda 函数的声明是用 auto 关键字,没有 T。解决方法很简单:需要获取一个变量的类型,当然是用 decltype 关键字:

auto f = [](auto&& x) {	// 注意万能引用的形式为auto&&
    return func(normalize(std::forward(x)));
};

如果你对万能引用的原理:引用折叠(见 Item 28)比较熟悉,看到这里可能会有些心存疑虑:假设入参类型为 Widget,当入参为右值 Widget&& 时,对于模板函数,std::forward(param) 会被实例化为 std::forward(param)(T&& 对应 Widget&&,T 对应 Widget),而这里我们用 decltype(x) 得到的调用是 std::forward(param)。这样有没有问题呢?

让我们通过源码来考察。std::forward 的实现如下:

template
T&& forward(remove_reference_t& param)
{
	return static_cast(param);
}

当入参为 Widget&& 时,引用折叠发生前后分别为:

Widget&& && forward(Widget& param)
{
	return static_cast(param);
}
↓
Widget&& forward(Widget& param)
{
	return static_cast(param);
}

对比会发现这与 T 的类型是 Widget 时完全相同,所以,如此调用是没有问题的。

当然,以上讨论也都适用于可变参数:

auto f = [](auto&&... params) {
	return func(normalize(std::forward(params)...));
};
总结
    对 auto&& 参数使用 decltype 以转发它们。(复读标题ww)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/768720.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号