代码:
template <typename T, typename... Args>
unique_ptr<T> make_unique(Args&&... args) {
return unique_ptr<T>(new T(forward<Args>(args)...));
}
光看这个的话,可能你们会看晕头转向,但是经过我在2025.8.15 的凌晨1点多的不懈努力,终于是把这个搞懂了,我们一步一步来看这个代码,首先是template部分,你首先可能会发现,为什么会有两个模版参数?一个T一个Args,首先,这两个模版参数并不是一样的,你会发现后面的那三个点:...,这个代表这是一个类型包,也就是int ,double,long long这样的类型包,被集合成一个Args了,那么你可能又会问:Args&&...又代表什么?这是表达的是函数参数包,表达的是值啊什么的,比如42,3.14,2e9各种各样的值。到这里,你可能会想,&&不是右值引用吗?为什么要右值引用,万一来个左值不就炸啦?其实这里表达的是万能引用,模版参数加个&&就是万能引用了。好的,说远了,我们继续讲我们的问题:为什么有两个模版参数?其实,这里必须要两个(后面的是类型参数包),保证工厂函数的正确性,比如,有一个结构体dog里面有两个值,一个是string name,一个是 int age,那么当我们想要一个dog类型的智能指针的时候,那么必须要传入name和age,但是你怎么传呢?你需要这样创建(这里默认用unique_ptr):make_unique<dog>(“bai”,10);而dog就是模版参数T,而小括号里面的内容就是Args函数参数包里面的类型(string,int),对应的构造函数将他们赋值成为了(“bai”,10)。这就是类型参数包和函数参数包的作用,接下来附一张图:
好了,有了这张图我觉得就不需要我过多阐述了,我们继续看这个代码,我们看第二行开头的unique_ptr<T>,为什么是这个类型?因为我们最终make_unique的时候,返回的就是一个unique_ptr<T>,接下来就是make_unique了,这个没什么可说的,就是函数名称,括号里面的就是函数参数包,也就是值,保证了我们输入的时候是值,让编译器自动推断它的类型,最后return的是一个unique_ptr<T>类型。new T(.......)表达的是这是一个T类型的值,但是里面的内容我们要仔细讲讲。完美转发(forward)是什么,我们在传输的过程中,通常会遇见左值和右值,但是编译器很笨,可能转发的时候会将右值改为左值,完全违背了我们的意识,但是有了forward就不一样了,它可以完美的分辨什么是左值什么是右值,并且返回,这就完美的解决了我们所要面对的问题。还有一个问题,为什么后面加着...呢?这就是模式展开,目的是为了将每个类型都对应每个值。
这样的做法是正确的,我们来看一张图:

展开后,string 对应一个值,int对应一个值,这就是模式展开。当然我们还有简单展开
我们先看这张图,来了解一下这两个的区别。

简单展开和模式展开的区别在于,简单展开仅将参数包中的元素依次展开,而模式展开则是按照特定的匹配规则将类型与值一一对应。例如在模式展开中,每个类型都会对应一个特定的值,而简单展开只是将参数包中的内容线性展开,不进行复杂的匹配处理。通过这两张图的对比,我们可以清楚地看到模式展开的优势在于能够精准地匹配每个类型和对应的值,从而更高效地处理参数传递的问题。
也就是说,简单展开只是把值给你一个个罗列出来,但是模式展开直接就会把这个值的类型一一对应给你罗列出来,相比之下,模式展开更加常用,在对于结构体类型更加安全常用!
那么,什么时候用完美转发呢?

接来下请看代码:
#include <iostream>
#include <utility> // 为了 std::forward
// 处理左值的版本
void process(int& value) {
std::cout << "处理左值!" << std::endl;
}
// 处理右值的版本
void process(int&& value) {
std::cout << "处理右值!" << std::endl;
}
// 完美转发的包装函数
template <typename T>
void wrapper(T&& arg) {// T&&万能引用
process(std::forward<T>(arg)); // 关键点!完美转发
}
int main() {
int a = 10; // 左值
wrapper(a); // 传左值
wrapper(42); // 传右值
wrapper(std::move(a)); // 强制转成右值再传
return 0;
}
如果不想要完美转发,代码:return unique_ptr<T>(new T(args...));
如果你想要完美转发,代码:return unique_ptr<T>(new T(forward<Args>(args)...));
3万+

被折叠的 条评论
为什么被折叠?



