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

C++ 模板专题 - 类型擦除

一:概述

        C++ 中的类型擦除(Type Erasure)是一种技术,允许你在不暴露具体类型信息的情况下,通过统一的接口处理不同的类型。这种技术常用于实现泛型编程,特别是在需要支持多种不同类型的情况下,如容器、算法和接口。

        类型擦除通过隐藏类型信息,允许程序在运行时处理不同的类型。通常,这种技术涉及使用基类指针或模板来实现一种抽象,使得具体类型的细节在使用时被“擦除”。

二:示例:

#include <iostream>
#include <memory>
#include <vector>
#include <functional>// 抽象基类
class Any {
public:virtual ~Any() = default;virtual void call() const = 0;  // 虚函数
};// 模板派生类
template <typename T>
class AnyImpl : public Any {
public:AnyImpl(T value) : value_(value) {}void call() const override {value_();  // 调用存储的函数}private:T value_;
};// 类型擦除容器
class FunctionContainer {
public:template <typename T>void add(T func) {functions_.emplace_back(std::make_shared<AnyImpl<T>>(func));}void execute() const {for (const auto& func : functions_) {func->call();  // 调用每个函数}}private:std::vector<std::shared_ptr<Any>> functions_;
};// 测试
void hello() {std::cout << "Hello, World!" << std::endl;
}void goodbye() {std::cout << "Goodbye, World!" << std::endl;
}int main() {FunctionContainer container;container.add(hello);container.add(goodbye);container.execute();  // Output: Hello, World! Goodbye, World!return 0;
}
#include <iostream>
#include <memory>
#include <string>
#include <vector>class Object {public:template <typename T> explicit Object(const T& obj): object(std::make_shared<Model<T>>(std::move(obj))){}std::string getName() const { return object->getName(); }struct Concept {virtual ~Concept() {}virtual std::string getName() const = 0;};template< typename T > struct Model : Concept {explicit Model(const T& t) : object(t) {}std::string getName() const override {return object.getName();}private:T object;};std::shared_ptr<const Concept> object;
};void printName(std::vector<Object> vec){for (auto v: vec) std::cout << v.getName() << '\n';
}struct Bar{std::string getName() const {return "Bar";}
};struct Foo{std::string getName() const {return "Foo";}
};int main(){std::cout << '\n';std::vector<Object> vec{Object(Foo()), Object(Bar())};printName(vec);std::cout << '\n';}

三:C++ 标准库中的类型擦除:

    C++ 标准库中有一些使用类型擦除的例子,如 std::functionstd::any

  • std::function:可以存储任意可调用对象(函数、lambda、绑定表达式等),并提供统一的调用接口。
  • std::any:可以存储任意类型的值,同时提供类型安全的访问接口。
#include <any>
#include <iostream>int main()
{std::cout << std::boolalpha;// any typestd::any a = 1;std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';a = 3.14;std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';a = true;std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';// bad casttry{a = 1;std::cout << std::any_cast<float>(a) << '\n';}catch (const std::bad_any_cast& e){std::cout << e.what() << '\n';}// has valuea = 2;if (a.has_value())std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';// reseta.reset();if (!a.has_value())std::cout << "no value\n";// pointer to contained dataa = 3;int* i = std::any_cast<int>(&a);std::cout << *i << '\n';
}
#include <functional>
#include <iostream>struct Foo
{Foo(int num) : num_(num) {}void print_add(int i) const { std::cout << num_ + i << '\n'; }int num_;
};void print_num(int i)
{std::cout << i << '\n';
}struct PrintNum
{void operator()(int i) const{std::cout << i << '\n';}
};int main()
{// store a free functionstd::function<void(int)> f_display = print_num;f_display(-9);// store a lambdastd::function<void()> f_display_42 = []() { print_num(42); };f_display_42();// store the result of a call to std::bindstd::function<void()> f_display_31337 = std::bind(print_num, 31337);f_display_31337();// store a call to a member functionstd::function<void(const Foo&, int)> f_add_display = &Foo::print_add;const Foo foo(314159);f_add_display(foo, 1);f_add_display(314159, 1);// store a call to a data member accessorstd::function<int(Foo const&)> f_num = &Foo::num_;std::cout << "num_: " << f_num(foo) << '\n';// store a call to a member function and objectusing std::placeholders::_1;std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);f_add_display2(2);// store a call to a member function and object ptrstd::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);f_add_display3(3);// store a call to a function objectstd::function<void(int)> f_display_obj = PrintNum();f_display_obj(18);auto factorial = [](int n){// store a lambda object to emulate "recursive lambda"; aware of extra overheadstd::function<int(int)> fac = [&](int n) { return (n < 2) ? 1 : n * fac(n - 1); };// note that "auto fac = [&](int n) {...};" does not work in recursive callsreturn fac(n);};for (int i{5}; i != 8; ++i)std::cout << i << "! = " << factorial(i) << ";  ";std::cout << '\n';
}

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

相关文章:

  • RuoYi-Vue项目 重点代码讲解
  • pandas习题 024:用字典构造 DataFrame
  • 如何在Node.js中执行解压缩文件操作
  • 梦熊 CSP-S模拟赛 T3 youyou 的序列 II
  • 记录下docker部署gitlab-ce-17.5版本及客户端git拉取方式配置
  • opencv-platform实现人脸识别
  • leetcode 有重复字符串的排列组合
  • 【大数据学习 | kafka】kafka的组件架构
  • Python基于TensorFlow实现简单循环神经网络回归模型(SimpleRNN回归算法)项目实战
  • torch.isclose
  • Python记录-字典
  • python读取学术论文PDF文件内容
  • 5550 取数(max)
  • Windows常用网络命令
  • 地磁传感器(学习笔记上)
  • 使用 NumPy 和 Matplotlib 进行高级数据可视化:实践指南
  • mysql 启动报错 ‘/var/run/mysqld/mysqld.sock‘
  • JAVA基础:常用类 (习题笔记)
  • element 按钮变形 el-button样式异常
  • Windows/Linux(服务器)查看显卡的名称
  • 算法基础 - 时间复杂度和空间复杂度(万字长文详解)
  • 【K8S系列】Kubernetes 中 Service IP 地址和端口不匹配问题及解决方案【已解决】
  • 10. 异常处理器
  • python查询并安装项目所依赖的所有包
  • istio多主集群架构验证方法
  • Java全栈经典面试题剖析8】JavaSE高级 -- 线程同步、 线程通信、死锁、线程池
  • linux 驱动, struct file , struct node, private_data
  • ubuntu 硬盘扩容
  • cm211-1刷机教程镜像包
  • Android 15自定义设置导航栏与状态栏,EdgeToEdge适配