gpt4 book ai didi

c++ - 基于类型映射的运行时类型选择

转载 作者:行者123 更新时间:2023-11-28 01:14:31 26 4
gpt4 key购买 nike

背景

我正在编写一个使用 USB 设备的应用程序。这包括基于 USB 供应商 ID 和产品 ID 发现我的应用程序可以使用的 USB 设备。然而,这些设备有时有多个可能工作的驱动程序,即应用程序实现,具体取决于平台和月相(客户遗留的东西)。所以我想使用 std::shared_ptr 和一系列不错的接口(interface)和东西来使用运行时多态性。

问题

我不知道如何根据给定的运行时键make_shared 特定类型的对象。至少不是在非丑陋的意义上。

目前的解决方案

我正在考虑以某种方式将类型值存储到 map known_drivers 中(在这个例子中是一个多重 map ,但差别不大)这样最后,根据数字值我可以构造一个不同的类类型并将其填充到 shared_ptr 中。

示例代码

#include <iostream>
#include <algorithm>
#include <iterator>
#include <map>
#include <memory>
#include <stdexcept>

using vendor_product_usb_id_t = std::pair<uint16_t, uint16_t>;

struct usb_device {
static std::shared_ptr<usb_device> open(vendor_product_usb_id_t);
virtual void do_stuff() = 0;
};

struct usb_device_using_driver_a : usb_device {
usb_device_using_driver_a() {throw std::runtime_error("Not supported on this platform");}
protected:
void do_stuff() override {}
};

struct usb_device_using_driver_b : usb_device {
protected:
void do_stuff() override {std::cout << "Stuff B\n";}
};


const std::multimap<vendor_product_usb_id_t, ??> known_drivers = {{{0x42,0x1337}, driver_a}, {{0x42,0x1337}, driver_b}};

std::shared_ptr<usb_device> usb_device::open(vendor_product_usb_id_t id) {
std::shared_ptr<usb_device> value;
for (auto [begin,end] = known_drivers.equal_range(id); begin != end; ++begin) {
try {
value = std::make_shared<*begin>();
} catch (std::exception& e) {
continue;
}
}
return value;
}

int main() {
auto device = usb_device::open(std::make_pair(0x42,0x1337));
if (device) {
device->do_stuff();
}
}

最佳答案

在 C++ 中存储类型并使用它来创建实例是不可能的,因为 C++ 还没有反射。

但是,factory pattern 可以满足您的需求和 virtual constructor idiom .

作为基本起点:

using vendor_product_usb_id_t = std::pair<uint16_t, uint16_t>;

struct usb_device {
using usb_ptr = std::shared_ptr<usb_device>;

virtual void do_stuff() = 0;

// virtual constructor
virtual usb_ptr create(vendor_product_usb_id_t) = 0;
};


struct usb_device_using_driver_a : usb_device {
usb_ptr create(vendor_product_usb_id_t) override {
return usb_ptr(new usb_device_using_driver_a);
}

void do_stuff() override {
std::cout << "usb_device_using_driver_a::do_stuff()" << std::endl;
}
};


struct usb_device_using_driver_b : usb_device {
usb_ptr create(vendor_product_usb_id_t) override {
throw std::runtime_error("Not supported on this platform");
}

void do_stuff() override {
std::cout << "usb_device_using_driver_b::do_stuff()\n";
}
};


class usb_device_factory {
public:

static usb_device::usb_ptr open(vendor_product_usb_id_t id) {
// note this map is static
// for simplicity changed the multimap to map
static std::map<vendor_product_usb_id_t, usb_device::usb_ptr> known_drivers = {
std::make_pair(std::make_pair(0x42,0x1337), usb_device::usb_ptr(new usb_device_using_driver_a())),
std::make_pair(std::make_pair(0x43,0x1337), usb_device::usb_ptr(new usb_device_using_driver_b())),
};

return known_drivers[id]->create(id);
}
};


int main() {
try {
auto device = usb_device_factory::open(std::make_pair(0x42,0x1337));
device->do_stuff();

// this will throw
device = usb_device_factory::open(std::make_pair(0x43,0x1337));
device->do_stuff();
}
catch(std::exception const& ex) {
std::cerr << ex.what();
}
}

Live .

不用虚构造函数也可以,但工厂模式的基本原则仍然适用:

using vendor_product_usb_id_t = std::pair<uint16_t, uint16_t>;


struct usb_device {
virtual void do_stuff() = 0;
};

using usb_ptr = std::shared_ptr<usb_device>;



struct usb_device_using_driver_a : usb_device {
void do_stuff() override {
std::cout << "usb_device_using_driver_a::do_stuff()" << std::endl;
}
};


struct usb_device_using_driver_b : usb_device {
void do_stuff() override {
std::cout << "usb_device_using_driver_b::do_stuff()\n";
}
};


class usb_device_factory {
public:

static usb_ptr open(vendor_product_usb_id_t id) {
// note this map is static
static std::map<vendor_product_usb_id_t, std::function<usb_ptr()>> known_drivers = {
std::make_pair(std::make_pair(0x42,0x1337), []() { return usb_ptr(new usb_device_using_driver_a()); } ),
std::make_pair(std::make_pair(0x43,0x1337), []() { return usb_ptr(new usb_device_using_driver_b()); } ),
};

return known_drivers[id]();
}
};


int main() {
try {
auto device = usb_device_factory::open(std::make_pair(0x42,0x1337));
device->do_stuff();

device = usb_device_factory::open(std::make_pair(0x43,0x1337));
device->do_stuff();
}
catch(std::exception const& ex) {
std::cerr << ex.what();
}
}

Live .

对于这两种变体,都可以在运行时使用额外的驱动程序扩展 map 。由于它存储在“动态”映射中,因此没有限制驱动程序数量的开关。

编辑:

刚刚发现一个类似的问题,答案和我的基本一样,unsing factory pattern with virtual constructors:

Can objects be created based on type_info?

关于c++ - 基于类型映射的运行时类型选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59136695/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com