一个类似 std::访问的函数,用于访问多态类型
A std::visit-like function for visiting over polymorphic types
我最近一直在尝试C++17的std::variant
和std::visit
,我发现它非常强大。 我特别喜欢在几个变体对象上创建访客模式的能力。 以下是我的意思的一个例子:
std::variant<int, float, char> v1 { 's' };
std::variant<int, float, char> v2 { 10 };
std::visit(overloaded{
[](int a, int b) { },
[](int a, float b) { },
[](int a, char b) { },
[](float a, int b) { },
[](auto a, auto b) { }, // << default!
}, v1, v2);
有关完整详细信息,请参阅 https://www.bfilipek.com/2018/09/visit-variants.html。 鉴于此,我想知道是否有可能基于多态类型而不是变体对象编写类似的代码。
考虑一个场景,我们使用动态多态性和父对象来编写通用接口。 然后我们要实现依赖于几种多态类型的某个功能,即
void fun(IFoo* ptr_foo, IBar* ptr_bar) {
{
Foo1* child_foo = dynamic_cast<Foo1*>(ptr_foo);
Bar1* child_bar = dynamic_cast<Bar1*>(ptr_bar);
if(child_foo && child_bar) { return fun(child_foo, child_bar) }
}
// ... other cases
{
Foo1* child_foo = dynamic_cast<Foo1*>(ptr_foo);
BarN* child_bar = dynamic_cast<BarN*>(ptr_bar);
if(child_foo && child_bar) { return fun(child_foo, child_bar) }
}
// ... other cases
{
FooN* child_foo = dynamic_cast<FooN*>(ptr_foo);
BarN* child_bar = dynamic_cast<BarN*>(ptr_bar);
if(child_foo && child_bar) { return fun(child_foo, child_bar) }
}
throw std::runtime_error{};
}
我知道以上情况远非最佳,但只是试图使场景尽可能清晰。
在这种情况下,使用虚拟函数进行fun
似乎并不简单,因为它取决于两个输入的类型。 此外,我们试图避免使用这些功能的虚拟方法, 因为我们更喜欢保持IFoo
的界面或IBar
这些外部函数的不可知性。
对于访问函数的多个输入对象,使用访问者模式似乎也不合理。
最简单的方法似乎是使用我上面展示的示例实现dynamic_cast
, 但是,当我们从 1 个输入增加到 N 个输入时,要写入的案例数量会迅速增加。 不过,上面的std::variant
+std::visit
方法非常简洁明了地涵盖了这种情况。
总结一下,我们的约束/要求是:
- 将多个多态对象作为输入的访问者模式
- 非关键运行时性能(因此说使用
dynamic_cast
就可以了( - 具有最少的样板,类似于
std::visit
方法
这可能吗?
我正在考虑编写一个可变递归模板化函数,类似于std::visit
, 这将自动生成要检查的所有类型案例。 使用示例如下:visitPolymorphic<tuple<Foo1, Foo2>,tuple<Bar1, Bar2, Bar3>>(ptr_foo, ptr_bar)
这将在不同的模板输入类型上,并调度正确的调用。
对此有什么想法吗?
你也可以在那里使用std::variant
:
struct Foo1;
struct Foo2;
struct Foo3;
using FooVariant = std::variant<Foo1*, Foo2*, Foo3*>;
struct IFoo
{
virtual ~IFoo() = default;
FooVariant AsVariant() = 0;
// ...
};
struct Foo1 : IFoo
{
FooVariant AsVariant() override { return this;}
// ...
};
// Same for FooX
struct Bar1;
struct Bar2;
struct Bar3;
using BarVariant = std::variant<Bar1*, Bar2*, Bar3*>;
struct IBar
{
virtual ~IBar() = default;
BarVariant AsVariant() = 0;
// ...
};
struct Bar1 : IBar
{
BarVariant AsVariant() override { return this;}
// ...
};
// Same for BarX
然后
void fun(IFoo& foo, IBar& bar) {
std::visit(overloaded{
[](Foo1* a, Bar1* b) { /*..*/ },
[](Foo2* a, Bar2* b) { /*..*/ },
[](Foo3* a, auto* b) { /*..*/ },
[](auto* a, auto* b) { /*..*/ }, // << default!
},
foo.AsVariant(), bar.AsVariant()
);
}
如果您不希望在界面中使用虚拟AsVariant()
(但使用dynamic_cast
(,您可能仍然有空闲功能:
FooVariant AsVariant(IFoo& foo)
{
if (auto* p = dynamic_cast<Foo1*>(&foo)) {
return p;
}
if (auto* p = dynamic_cast<Foo2*>(&foo)) {
return p;
}
if (auto* p = dynamic_cast<Foo3*>(&foo)) {
return p;
}
throw std::runtime_error("Invalid type");
}
- 如何在函数外部访问函数中局部变量的值?
- UChildActorComponent的ChildActorClass中的访问函数
- 访问函数变体时"Invalid conversion"错误
- 在将向量作为参数传递给函数后,我无法访问函数中向量的元素
- 在64位DLL中访问函数的错误
- 访问函数中 const char *arr[] 的元素
- 访问函数的调用方类型
- 访问函数中的使用声明:与范围相关的问题
- 通过 -> 语法 c++ 从指针访问函数
- 在函数中使用 const 引用参数访问函数中成员的最佳实践 C++.
- 从另一个文件(C++,QT)访问函数未解析的外部
- 如何从主(C )访问函数中的值
- 访问函数 c++ 中的全局变量
- C++ GoogleTest 使用夹具 - 无法访问函数指针定义
- 在不知道名称的情况下访问函数参数
- C++:直接访问器或类内的访问函数
- 无法从对象访问函数
- 类的2D矢量在访问函数时出错
- 为什么在C++中访问函数时没有对象
- 我无法使用指针数组从main访问函数(在类中)