【发布时间】:2020-07-06 15:45:38
【问题描述】:
我不希望在 C++ 中实现我想要实现的目标,但也许我错了,因为我之前关于 bidirectional static mapping 的问题得到了一个不太可能的答案。
我有一组特定类型,一个带有表示类型的键的枚举,以及一个接受提到的类型作为模板参数的模板句柄类型。
struct foo {};
struct bar {};
enum class types { foo, bar };
template<typename T>
struct qux {};
我希望能够在运行时将types::foo 映射到foo。大多数时候foo 会被用作qux 的模板参数,所以types::foo 到qux<foo> 的映射也很好,但我觉得如果一个可能,那么另一个也是。
我之所以提到这一点是因为重要的是要注意qux 是一个简单的类似句柄的类型,它只包含一个索引并按值传递,并且有很多模板函数将qux<T> 作为一个参数。
这使得多态性——这种情况下的标准解决方案——不是一个明显的选择。
虽然有时我需要创建一个qux<T>,而只有一个变量持有types 值,所以它必须以某种方式映射到正确的类型。
到目前为止,我一直在做的只是switching,每次我必须这样做,但我达到了需要维护太多switches 的地步。
我没有看到更好的解决方案,所以我想做的是在代码中创建一个 swich 或其他机制,它将获取 types 值并返回......这会让我创建一个具有相关类型的qux<T>。
最终它会像这样工作。
template<typename T>
void baz(qux<T> q) { /* ... */ }
// Somewhere else...
types t = get_type(); // Read type at runtime.
baz(create_object(t)); // Calls adequate baz specialization based on what value t contains.
虽然我不知道如何实现create_object 函数。
我已经尝试过的:
-
std::variant小心使用emplace和index- 快速解决无法从单个函数返回不同类型的问题; -
clever use of conversion operators - 不允许我调用以
qux<T>作为参数的正确模板函数,因为它没有决定应该调用哪个专业化; - external polymorphism - 无法返回不同的类型;
- 修改了this answer 中提出的模板特化循环,它寻找正确的
types值并返回映射类型 - 由于无法返回不同类型而失败 - 或使用auto参数调用 lambda - 这也失败为它尝试多次专门化 lambda。
【问题讨论】:
-
模板在编译时被实例化。
qux::<foo>需要在编译时实例化,如果映射发生在运行时就不会发生这种情况。 -
如果你走这条路,你在这里真正能做的最好的事情是执行某种类型擦除,这样你就有一个类型擦除的类(如
void*),它从一些@返回987654352@ 函数接收一些输入,例如来自type_info结构的 hash_code,并正确映射到返回qux<foo>类型擦除为void*的函数,然后调用者必须执行static_cast恢复类型。 -
std::variant似乎正是这里的正确工具。你尝试了什么?在您的示例中,create_object应该返回std::variant<qux<foo>, qux<bar>>并且您将调用baz和std::visit([&](auto &&x) -> decltype(auto) { return baz(std::forward<decltype(x)>(x)); }, create_object(t))(是的,咒语很长,但是要完成这项工作还有很多工作要做)。哎呀,std::variant工作得很好,它可以直接替换types:using types = std::variant<std::type_identity<foo>, std::type_identity<bar>>,这可能有助于清理事情(或者可能不会,idk)。 -
@Vennor 我已经去那里简化了我的答案。我不知道为什么我把它弄得这么复杂。如果您在
types中实现了std::visit,那么您基本上已经将types变成了std::variant(std::variant基本上是std::visit)。我的建议让create_object返回std::variant只是这个想法的一种变体。
标签: c++