模板类 的完美转发

通过一个小List,实现模拟迭代器,之前很少写过模板的东西,起初我认为和普通函数一样,但实际中遇到了一些问题

如下函数

错误的万能引用

template <typename T>
class A{
    func(T &&value);
}

实际上 由于T是模板类的关系,这样写在func中 T不能起到推导作用,func的参数只是一个普通的右值引用参数

在模板类中实现万能的引用函数。即完美转发,需要再使用一个新的模板类型

template<typename T>
class List{
    //...

    template <typename U>
        void insert_front(U &&value) {
        //...   
        ListItem <T>*temp = new ListItem<T>(std::forward<U>(value));
        //...
        }
    //...
     }

其中类ListItem 拥有接受右值和左值的构造 insert_front函数可以成功实现完美转发

但事实上,这样仍然存在一个问题,如此设计出来的参数U和T实际上并不相关的。违背设计初衷。
如果List被初始化为一个int容器,那么实际上insert_front仍然可以传入其他类型参数。

可以通过如下方法

 static_assert(std::is_same<std::decay_t<U>,std::decay_t<T>>::value, 
                  "U must be the same as T");

函数is_same() 即判断T与U的类型是否一致。
decay_t() cppreference 中以下6个判断均为true ,他会去掉const ,指针,和引用(包括左右值)属性来判断

int main()
{
    std::cout << std::boolalpha
              << decay_equiv<int, int>::value << '\n'
              << decay_equiv<int&, int>::value << '\n'
              << decay_equiv<int&&, int>::value << '\n'
              << decay_equiv<const int&, int>::value << '\n'
              << decay_equiv<int[2], int*>::value << '\n'
              << decay_equiv<int(int), int(*)(int)>::value << '\n';
}

这是比较不错的办法,但实际上还是不可靠。List只是希望能够将左右值划分为一类,这样会使指针或者const类型相混淆。

本例可以使用如下办法完美解决

这是boost中的函数
#include <boost/type_traits/remove_cv_ref.hpp>

std::is_same<remove_cv_ref<T>, remove_cv_ref<U>>

意为仅去除引用属性

最后 iter还是有未解决的bug):

### C++ 移动语义和完美转发的概念 #### 移动语义 (Move Semantics) 移动语义是一种优化机制,允许对象通过转移其内部资源来减少不必要的拷贝操作。它主要依赖于右值引用 (`rvalue reference`) 和移动构造函数以及移动赋值运算符的实现[^1]。 在传统的 C++ 编程中,当一个对象被复制时,通常会调用拷贝构造函数或拷贝赋值运算符。这种行为可能导致性能开销较大的深拷贝操作。而引入移动语义后,在某些情况下可以避免这些昂贵的操作,转而直接接管原始对象的资源所有权。 以下是定义支持移动语义类的一个简单例子: ```cpp #include <iostream> #include <vector> class MyClass { public: // 拷贝构造函数 MyClass(const std::vector<int>& data) : data_(data) {} // 移动构造函数 MyClass(std::vector<int>&& data) noexcept : data_(std::move(data)) {} private: std::vector<int> data_; }; ``` 上述代码展示了如何为 `MyClass` 类提供移动构造函数以利用移动语义[^2]。 #### 完美转发 (Perfect Forwarding) 完美转发是指将模板参数中的实参原样无损地传递给另一个函数的能力。这使得我们可以在不丢失任何信息的情况下处理不同类型或者修饰状态下的参数(如左值、右值)。要实现完美的转发功能,则需要用到万能引用(Universal References)配合 `std::forward()` 函数完成转换工作[^3]。 下面是一个展示完美转发的例子: ```cpp template<typename T> void forward_function(T&& param){ another_function(std::forward<T>(param)); } ``` 在这个例子当中,无论传入的是 lvalue 还是 rvalue 参数,都可以正确地将其转发至目标函数 `another_function` 中去执行相应的逻辑[^3]。 --- ### 使用教程总结 为了有效地应用这两个概念,请遵循以下几点建议: - **对于需要频繁创建临时对象并分配大量内存的情况**,考虑添加自定义的移动构造函数与移动赋值运算符到你的类里头以便充分利用 move semantics 提供的好处。 - 当编写通用库组件时,如果涉及到未知类型的参数列表并且希望保持灵活性的同时还能保留效率的话,那么就应该采用 perfect forwarding 技术来设计接口形式。 最后提醒一下开发者们需要注意的一点就是关于异常安全性方面的问题;虽然大多数标准容器已经实现了 nothrow 版本的方法用于保障基本级别的安全承诺,但在自己动手实现的时候还是得小心谨慎对待可能发生的错误状况哦! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值