类型擦除TypeErase
来自CppCON2022
通过极其简单的方法实现:
头文件:
#pragma once #include <iostream> #include <memory> #include <vector> struct CommandConcept { virtual ~CommandConcept() = default; virtual void do_exec() = 0; virtual void do_info() const = 0; }; template< typename CommandT > struct CommandModel : public CommandConcept { CommandModel(CommandT cmd) : cmd_{ std::move(cmd) } {} void do_exec() override { adl_exec(cmd_);} void do_info() const override { adl_info(cmd_); } CommandT cmd_; }; inline void execALL(const std::vector<std::unique_ptr<CommandConcept>> & cmds){ for (auto & cmd : cmds){ cmd->do_exec(); } } inline void infoALL(const std::vector<std::unique_ptr<CommandConcept>>& cmds){ for (const auto& cmd : cmds){ cmd->do_info(); } }
源:
#include "TypeErase.h" using namespace std; struct CMD1 { void exec() { std::cout << "exec 1" << std::endl;} void info() const { std::cout << "I'm CMD1" << std::endl; } }; struct CMD2 { void exec() { std::cout << "exec 2" << std::endl;} void info() const { std::cout << "I'm CMD2" << std::endl; } }; struct CMD3 { void exec() { std::cout << "exec 3" << std::endl; } void info() const { std::cout << "I'm CMD3" << std::endl; } }; // adl exec void adl_exec(CMD1& cmd) { cmd.exec(); } void adl_exec(CMD2& cmd) { cmd.exec(); } void adl_exec(CMD3& cmd) { cmd.exec(); } // adl info void adl_info(const CMD1& cmd) { cmd.info(); } void adl_info(const CMD2& cmd) { cmd.info(); } void adl_info(const CMD3& cmd) { cmd.info(); } int main() { using CMDS = std::vector<std::unique_ptr<CommandConcept>>; std::unique_ptr<CommandModel<CMD1> > cmd1 = std::make_unique<CommandModel<CMD1>>(CMD1()); // also auto cmd1 = std::make... std::unique_ptr<CommandModel<CMD2> > cmd2 = std::make_unique<CommandModel<CMD2>>(CMD2()); std::unique_ptr<CommandModel<CMD3> > cmd3 = std::make_unique<CommandModel<CMD3>>(CMD3()); CMDS cmds; cmds.emplace_back(std::move(cmd1)); cmds.emplace_back(std::move(cmd2)); cmds.emplace_back(std::move(cmd3)); execALL(cmds); infoALL(cmds); }
可以看到 cmds可以插入不同的类。CMD1,CMD2,CMD3类中本质没有虚函数。