std::variant 和 std::visitor 是否意味着我的代码可以在编译时解析?

问题描述 投票:0回答:1

我有两个结构

A
B
共享相同的接口
foo
我希望能够根据上下文使用
A
B
,因此使用
std::variant
似乎在这里很有趣。

结构

C
封装了变体并提供了
foo
的实现,隐藏了对
std::visit
的调用。 然后,最终用户可以像使用
C
A
一样使用
B
(参见示例函数
dosomething

#include <variant>
#include <cstdio>

struct A   {  void foo() { printf ("[A::foo]\n");  }  };
struct B   {  void foo() { printf ("[B::foo]\n");  }  };

struct C
{
    C() {};

    template<typename T>  C (T&& t) : v(t) {}

    void foo()  {  std::visit ([](auto&& arg)  {  arg.foo();  }, v); }

    std::variant<A,B> v;
};

void dosomething (C c1)
{
    C c2;

    c1.foo(); // acts like a B
    c2.foo(); // acts like a A
}

int main(int argc, char **argv)
{
    dosomething (B());
}

显然,我可以轻松地将

C
定义为具有虚拟方法
foo
的接口,然后使
A
B
继承自
C
但我特别想避免由于动态多态性而潜在的过载 因为实际的
foo
可能非常简单(例如只是一个补充)并且经常被调用。

问题 1 这种设计是否确保可以在编译时知道使用

dosomething
对象对
B
的调用是 实际调用
B::foo
?换句话说,由于
std::variant
,我们仍然有一个(可能成本高昂的)间接吗?

问题 2 避免出于性能考虑的动态多态性的最佳替代方案是什么?我了解静态多态性,但最终,人们必须处理 使用像

Base<A>
Base<B>
这样的模板类,我需要最终用户只看到一个类,就像我的示例中的 struct
C
一样。

更新请注意,在我的上下文中,

dosomething
的原型无法更改,特别是无法模板化,这使得设计变得更加困难。

c++ variant static-polymorphism run-time-polymorphism
1个回答
0
投票

使用模板:

template <class C>
void dosomething (C& c) {
    c.foo();
}

如果您使用 C++20,您也可以使用概念来执行契约:

#include <cstdio>

template <typename T>
concept Fooable = requires(T t) {
    t.foo();
};

struct A {
    void foo() { std::puts("A"); }
};

struct B {
    void foo() { std::puts("B"); }
};

template <Fooable C>
void dosomething(C& c) {
    c.foo();
}

int main() {
    A a;
    B b;
    dosomething(a);
    dosomething(b);
}
© www.soinside.com 2019 - 2024. All rights reserved.