官方网站下载免费app,1g内存的服务器可以建设几个网站,网络搭建学什么,wordpress 顶部公告文章目录 一、std::forward、万能引用与完美转发1、万能引用2、类型推导3、引用折叠4、std::forward 概述 std::forward是C11中引入的一个函数模板#xff0c;用于实现完美转发。它的作用是根据传入的参数#xff0c;决定将参数以左值引用还是右值引用的方式进行转发。 传统上… 文章目录 一、std::forward、万能引用与完美转发1、万能引用2、类型推导3、引用折叠4、std::forward 概述 std::forward是C11中引入的一个函数模板用于实现完美转发。它的作用是根据传入的参数决定将参数以左值引用还是右值引用的方式进行转发。 传统上当一个左值传递给一个函数时参数会以左值引用的方式进行传递当一个右值传递给一个函数时参数会以右值引用的方式进行传递。完美转发是为了解决传递参数时的临时对象右值被强制转换为左值的问题。std::forward实现完美转发主要用于以下场景提高模板函数参数传递过程的转发效率。 一、std::forward、万能引用与完美转发
1、万能引用 对于形如T的变量或者参数如果T可以进行推导那么T称之为万能引用。换句话说对于形如T的类型来说其既可以绑定左值又可以绑定右值而这个的前提是T需要进行推导。最常见的万能引用方式如以下两种 函数模板
templatetypename T
void f(T param); // 存在类型推导param是一个万能引用auto类型推导
auto var var1; // 存在类型推导var是一个万能引用注意只有当发生自动类型推断时例如函数模板的类型自动推导T 才是万能引用。下面一个示例中的 并不是一个万能引用例如 templatetypename T
void f( T param); // 这里T的类型需要推导所以是一个 universal referencestemplatetypename T
class Test {Test(Test rhs); // Test是一个特定的类型不需要类型推导所以表示右值引用
};2、类型推导 万能引用进行类型推导时需要推导出T中的T的真实类型若传入的参数是一个左值则T会被推导为左值引用而如果传入的参数是一个右值则T会被推导为原生类型非引用类型。 对于万能引用来说条件之一就是类型推导但是类型推导是万能引用的必要非充分条件也就是说参数必须被声明为T形式不一定是万能引用。示例如下 templatetypename T
void func(std::vectorT t); // t是右值引用调用func时会执行类型推导但是参数t的类型声明的形式并非T 而是std::vector 。 之前强调过万能引用必须是T 才行因此t是一个右值引用如果尝试将左值传入编译器将会报错 std::vectorint v;
fun(v); // 编译错误不能将左值绑定到右值形如const T的方式也不是万能引用 templatetypename T
void f(const T t); // t是右值引用int main() {int a 0;f(a); // 错误
}3、引用折叠 引用折叠是一种特性允许在模板元编程中使用引用类型的参数来创建新的引用类型。由于存在T这种万能引用类型当它作为参数时有可能被一个左值/左值引用或右值/右值引用的参数初始化这需要通过类型推导推导后得到的参数类型会发生类型变化这种变化就称为引用折叠。 根本原因是因为C中禁止reference to reference所以编译器需要对四种情况 、 , 进行处理将他们折叠成一种单一的reference。引用折叠的规则如下如果两个引用中至少其中一个引用是左值引用那么折叠结果就是左值引用否则折叠结果就是右值引用。示例如下 using T int ;
T r1; // int r1 - int r1
T r2; // int r2 - int r2using U int ;
U r3; // int r3 - int r3
U r4; // int r4 - int r4下面是一个具体的示例可以看下对应的推导过程 templatetypename T
void func(T t) {cout hello world endl;
}int main() {int a 1;int b a;func(a); // T 推导成 int ; T int int func(b); // T 推导成 int ; T int int func(1); // T 推导成 int; T int func(std::move(a)); // T 推导成 int ; T int int return 0;
}4、std::forward 完美转发是为了解决传递参数时的临时对象右值被强制转换为左值的问题std::forward源码如下 templateclass T
T forward(typename std::remove_referenceT::type t) noexcept {return static_castT(t);
}template class T
T forward(typename std::remove_referenceT::type t) noexcept {return static_castT(t);
}其内部实现只有一行代码即static_castT(t)使用static_cast进行类型转换与std::move()实现方式类似。结合前面介绍的引用折叠当接收一个左值作为参数时std::forward()返回左值引用相应的当接收一个右值作为参数时std::forward()返回右值引用。 版本一没有实现完美转发 下面给出一个案例没有实现完美转发如下 #include iostreamtemplate typename T
void wrapper(T u) {fun(u);
}class MyClass {};void fun(MyClass a) { std::cout in fun(MyClass)\n; }
void fun(const MyClass a) { std::cout in fun(const MyClass)\n; }
void fun(MyClass a) { std::cout in fun(MyClass )\n; }int main(void) {MyClass a;const MyClass b;fun(a);fun(b);fun(MyClass());std::cout ----- Wrapper ------\n;wrapper(a);wrapper(b);wrapper(MyClass());return 0;
}输出结果 in func(MyClass)
in func(const MyClass)
in func(MyClass )
----- Wrapper ------
in func(MyClass)
in func(const MyClass)
in func(const MyClass)Process returned 0 (0x0) execution time : 0.253 s
Press any key to continue.最后一行函数调用结果不符合预期传入的是MyClass 右值引用预期调用fun(MyClass a)实际上调用的却是fun(const MyClass a)。调用wrapper函数时触发拷贝构造基于右值创建了左值u即wrapper函数的参数u的实际类型是const MyClass匹配的是fun(const MyClass a) 版本二使用std::forward实现完美转发 使用万能引用和完美转发来修改前面的例子如下 #include iostreamtemplate typename T
void wrapper(T u) { // 万能引用func(std::forwardT(u)); // 完美转发
}class MyClass {};void func(MyClass a) { std::cout in func(MyClass)\n; }
void func(const MyClass a) { std::cout in func(const MyClass)\n; }
void func(MyClass a) { std::cout in func(MyClass )\n; }int main(void) {MyClass a;const MyClass b;func(a);func(b);func(MyClass());std::cout ----- Wrapper ------\n;wrapper(a);wrapper(b);wrapper(MyClass());return 0;
}输出结果 in func(MyClass)
in func(const MyClass)
in func(MyClass )
----- Wrapper ------
in func(MyClass)
in func(const MyClass)
in func(MyClass )Process returned 0 (0x0) execution time : 0.210 s
Press any key to continue.输出结果符合预期使用std::forward实现了完美转发。 注意std::forward()建议仅用于模板函数对于非模板的因为不涉及到类型推导所以使用完美转发是没有意义的。 https://mp.weixin.qq.com/s/bT–OIA7X8Uohxl_q1O98A