c++ - 带有 std::variant 或 union 包装器的通用接口(interface)

标签 c++ interface dispatch

此问题与 Enforcing a common interface with std::variant without inheritance 相关.

这个问题和这个问题之间的区别是,我不介意继承,我只是在寻找以下结构/类...

struct Parent { virtual int get() = 0; };
struct A : public Parent { int get() { return 1; } };
struct B : public Parent { int get() { return 2; } };
struct C : public Parent { int get() { return 3; } };

...自动“组装”到模板中:

template<typename PARENT, typename... TYPES>
struct Multi
{
    // magic happens here
}

// The type would accept assignment just like an std::variant would...
Multi<Parent, A, B, C> multiA = A();
Multi<Parent, A, B, C> multiB = B();
Multi<Parent, A, B, C> multiC = C();

// And it would also be able to handle virtual dispatch as if it were a Parent*
Multi<Parent, A, B, C> multiB = B();
multiB.get(); // returns 2

这可能吗?如果是这样,怎么办?我想避免使用处理指针,因为使用 std::variant/unions 的目的是使内存连续。

最佳答案

您无法自动将其设置为允许 multiB.get(),但您可以允许 multiB->get()(*multiB).get() 甚至隐式转换,通过提供运算符重载:

template<typename Base, typename... Types>
struct Multi : std::variant<Types...>
{
    using std::variant<Types...>::variant;

    operator Base&()               { return getref<Base>(*this); }
    Base& operator*()              { return static_cast<Base&>(*this); }
    Base* operator->()             { return &static_cast<Base&>(*this); }

    operator const Base&() const   { return getref<const Base>(*this); }
    const Base& operator*() const  { return static_cast<const Base&>(*this); }
    const Base* operator->() const { return &static_cast<const Base&>(*this); }

private:
    template<typename T, typename M>
    static T& getref(M& m) {
        return std::visit([](auto&& x) -> T& { return x; }, m);
    }
};

您以前在使用标准库中的迭代器时可能遇到过这种情况。

示例:

int main()
{
    Multi<Parent, A, B, C> multiA = A();
    Multi<Parent, A, B, C> multiB = B();
    Multi<Parent, A, B, C> multiC = C();

    // Dereference
    std::cout << (*multiA).get();
    std::cout << (*multiB).get();
    std::cout << (*multiC).get();

    // Indirection
    std::cout << multiA->get();
    std::cout << multiB->get();
    std::cout << multiC->get();

    // Implicit conversion
    auto fn = [](Parent& p) { std::cout << p.get(); };
    fn(multiA);
    fn(multiB);
    fn(multiC);
}

输出:

123123123

关于c++ - 带有 std::variant 或 union 包装器的通用接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73229272/

相关文章:

java - 启用 Java Swing 日志记录( key 分配)

c++ - 初始化不可复制和不可移动类的元组

c++ - 如何修复这个: Argument of type “const char*” is incompatible with the parameter of type "char** [duplicate]

java - 服务器启动后界面卡住

ios - 为什么我的金额数组没有返回任何内容?

java - activemq 通配符消费者如何工作?

c++ - 未解析的外部符号

c++ - 编译错误VTK,C++

c++ - c# 在 C++ 中重写的方法

Java模式改变API接口(interface)名称?