当前位置: 首页 > news >正文

条款6:auto推导若非己愿,使用显式类型初始化惯用法

一、代理类

所谓的代理类就是以模仿和增强一些类型的行为为目的存在的类

class MyArray
{
public:class MyArraySize{public:MyArraySize(int size) : theSize(size) {}int size() const { return theSize; }operator int() const { return theSize; }private:int theSize;};MyArray(MyArraySize size) : size_(size), data_(new int[size.size()]) {}int operator[](int index){return data_[index];}bool operator==(const MyArray &temp){return data_ == temp.data_;}MyArraySize size() { return size_; }private:int *data_;MyArraySize size_;
};class MyArray_
{
public:// C++ 11之前没有explicitMyArray_(int size) : size_(size), data_(new int[size]) {}private:int *data_;int size_;
};void func1(MyArray arr)
{
}void func2(MyArray_ arr)
{
}int main()
{func2(10);func1(10);  // 错误,不能进行两次类型转换func1(MyArray(10)); // 通过代理类,可以避免上面隐式转换的情况return 0;myArray arr(10);auto size = arr.size();  // auto 推导为MyArray::MyArraySizeint size_ = arr.size();  // 因为存在operator int()隐式类型转换
}

二、临时变量的引用不要用引用来接

#include <vector>
#include <iostream>class A
{
public:A() { std::cout << "A::A()" << std::endl; }A(int data) : _data(data) { std::cout << "A::A(int data)" << std::endl; }A(const A &a) : _data(a._data){std::cout << "A::A(const A &a)" << std::endl;}A(A &&a) : _data(a._data){std::cout << "A::A(A &&a)" << std::endl;}~A() { std::cout << "A::~A()" << std::endl; }int _data{100};
};std::vector<A> func()
{return {A(1), A(2), A(3), A(4), A(5)};
}int main()
{A aaa = func()[2];    // 发生拷贝A &bbb = func()[3];   // 错误,引用了一个临时变量return 0;
}
#include <vector>
#include <iostream>std::vector<bool> features()
{return {true, true, true, false, false};
}int main()
{bool highPriority = features()[4];auto highPriority = features()[4]; // 错误写法,推导为引用类型的代理类// auto推到为std::vector<bool>::reference// reference在vector中其实是一个代理类auto highPriority_ = static_cast<bool>(features()[4]);return 0;
}

三、expressin template

#include <cassert>
#include <iostream>
#include <vector>template <typename Derived>
void func(Base<Derived> derived)
{derived.name();
}// https://blog.csdn.net/HaoBBNuanMM/article/details/109740504
// CRTP中的基类模板
template <typename E>
class VecExpression
{
public:// 通过将自己static_cast成为子类,调用子类的对应函数实现实现静态多态double operator[](size_t i) const { return static_cast<E const &>(*this)[i]; }size_t size() const { return static_cast<E const &>(*this).size(); }
};// 将自己作为基类模板参数的子类 - 对应表达式编译树中的叶节点
class Vec : public VecExpression<Vec>
{std::vector<double> elems;public:double operator[](size_t i) const { return elems[i]; }double &operator[](size_t i) { return elems[i]; }size_t size() const { return elems.size(); }Vec(size_t n) : elems(n) {}Vec(std::initializer_list<double> init){for (auto i : init)elems.push_back(i);}// 赋值构造函数可以接受任意父类VecExpression的实例,并且进行表达式的展开// (对应表达式编译树中的赋值运算符节点)template <typename E>Vec(VecExpression<E> const &vec) : elems(vec.size()){for (size_t i = 0; i != vec.size(); ++i){elems[i] = vec[i];}}
};// 将自己作为基类模板参数的子类 - 对应表达式编译树中的二元运算符输出的内部节点
// 该结构的巧妙之处在于模板参数E1 E2可以是VecSum,从而形成VecSum<VecSum<VecSum ... > > >的嵌套结构,体现了表达式模板的精髓:将表达式计算改造成为了构造嵌套结构
template <typename E1, typename E2>
class VecSum : public VecExpression<VecSum<E1, E2>>
{E1 const &_u;E2 const &_v;public:VecSum(E1 const &u, E2 const &v) : _u(u), _v(v){assert(u.size() == v.size());}double operator[](size_t i) const { return _u[i] + _v[i]; }size_t size() const { return _v.size(); }
};// 对应编译树上的二元运算符,将加法表达式构造为VecSum<VecSum... > >的嵌套结构
template <typename E1, typename E2>
VecSum<E1, E2> const operator+(E1 const &u, E2 const &v)
{return VecSum<E1, E2>(u, v);
}// 主函数入口
int main()
{// 创建3个叶子节点Vec v0 = {1.0, 1.0, 1.0}; Vec v1 = {2.0, 2.0, 2.0}; Vec v2 = {3.0, 3.0, 3.0}; auto v4 = v0 + v1;  //auto 推导为VecSum<Vec, Vec> v4,这也是一个代理类// 如果想要的不是这种类型// 解决方案1Vec v4 = v0 + v1;// 解决方案2auto v4 =static_cast<Vec>( v0 + v1);return 0;
}

http://www.lryc.cn/news/509253.html

相关文章:

  • 蓝桥杯物联网开发板硬件组成
  • 视频汇聚融合云平台Liveweb一站式解决视频资源管理痛点
  • (aaai2025) FD2-Net: Frequency-Driven Feature Decomposition Network
  • 深度学习之目标检测——RCNN
  • 2014年IMO第3题
  • 国高材服务 | 高分子结晶动力学表征——高低温热台偏光显微镜
  • 跨站请求伪造之基本介绍
  • Hadoop集群(HDFS集群、YARN集群、MapReduce​计算框架)
  • 单元测试(UT,C++版)经验总结(gtest+gmock)
  • Mysql高级部分总结(二)
  • 纠正一下网络管理
  • homebrew,gem,cocoapod 换源,以及安装依赖
  • Java字符串的|分隔符转List实现方案
  • Kafka可视化工具 Offset Explorer (以前叫Kafka Tool)
  • DeepWalk 原理详解
  • GitLab安装|备份数据|迁移数据及使用教程
  • 嵌入式linux驱动框架 I2C系统驱动程序模型分析
  • 深度学习实验十七 优化算法比较
  • 一个双非选手的秋招总结
  • 如何提高永磁电动机的节电效果
  • 在一个服务器上抓取 Docker 镜像并在另一个服务器上运行
  • 开源轮子 - Logback 和 Slf4j
  • 内部知识库的未来展望:技术融合与用户体验的双重升级
  • 【Linux系列】Shell 命令:`echo ““ > img.sh`及其应用
  • 【RAG实战】语言模型基础
  • 【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等
  • 我的 2024 年终总结
  • STM32CUBEMX+STM32H743ZIT6+IAP+UART在线升级初始化和代码解析
  • 半连接转内连接 | OceanBase SQL 查询改写
  • Git使用经历