c++ - 类型删除 : Retrieving value - type check at compile time

标签 c++ c++11 templates type-erasure crtp

我有一组有限的非常不同的类型,我想从中将实例存储在一个集合中,特别是 map 。为此,我使用类型删除惯用语,即。我有一个非模板化的基类,模板化的、类型特定的类从中继承:

struct concept
{
   virtual std::unique_ptr<concept> copy() = 0; // example member function
};

template <typename T>
struct model : concept
{
   T value;
   std::unique_ptr<concept> copy() override { ... }
}

然后我将 unique_ptr 存储到我的 map 中的概念。为了检索值,我有一个模板化函数,它对指定类型进行动态转换。

template <typename T>
void get(concept& c, T& out) {
   auto model = dynamic_cast<model<T>>(&c);
   if (model == nullptr) throw "error, wrong type";
   out = model->value;
}

我不喜欢这个解决方案的一点是,指定错误的 T 只会在运行时检测到。我真的很喜欢这在编译时完成。

我的选择如下所示,但我认为它们在这里无济于事:

  • 通过将每种类型的自由函数指定为重载或模板函数来使用临时多态性,但我不知道将结果存储在何处。

    • 使用 CRTP 是行不通的,因为基类需要模板化。

    • 从概念上讲,我需要一个虚函数,它采用将存储结果的类的实例。但是,由于我的类型根本不同,因此需要对此类进行模板化,这不适用于虚拟。

无论如何,我什至不确定这在逻辑上是否可行,但如果有办法做到这一点,我将非常高兴。

最佳答案

对于一组有限的类型,最好的选择是variant。您可以通过指定对每个变体采取的操作来最轻松地操作变体,然后它可以正确地对变体进行操作。沿着这些线的东西:

std::unordered_map<std::string, std::variant<Foo, Bar>> m;

m["a_foo"] = Foo{};
m["a_bar"] = Bar{};

for (auto& e : m) {
    std::visit(overloaded([] (Foo&) { std::cerr << "a foo\n"; }
                          [] (Bar&) { std::cerr << "a bar\n"; },
               e.second);
}

std::variant 是 c++17,但通常预先在实验命名空间中可用,您也可以使用来自 boost 的版本。请参阅此处了解重载的定义:http://en.cppreference.com/w/cpp/utility/variant/visit (不幸的是,标准库没有提供一个小实用程序)。

当然,如果您期望某个键映射到特定类型,并且如果没有映射到特定类型则希望抛出错误,那么,仍然没有办法在编译时处理它。但这确实让您编写的访问者可以为变体中的每种类型执行您想要的操作,在某种意义上类似于虚拟,但实际上不需要具有通用接口(interface)或基类。

关于c++ - 类型删除 : Retrieving value - type check at compile time,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46041683/

相关文章:

java - 移植Java : C++ --> Class types

c++ - 如何生成一个范围内的随机数?

c++ - 按值复制而不是移动返回

PHP 模板方法 <?=$var?>?

c++ - 将C++中的 vector 元组包装为元组

c++ - "Protobuf compiler version doesn' t 匹配库版本 3.6.1"不使用系统 Protobuf 库时

c++ - 我如何将这些元素表达为 C++

c++ - 通知线程是否总是需要在修改期间锁定共享数据?

c++ - 编译时错误: Union default constructor is deleted

c++ - Switch 语句可变模板扩展