首页 > 解决方案 > 在 C++ 中存储视图类型的引用变体

问题描述

我有一个环境,我没有 C++17(C++14 ATM)功能也没有提升。

目前我有一个类负责在我们的域中的服务之间发送消息,这个类使用多种类型的寻址(两种类型都很重要),其中一种可以转换为另一种(假设 A 可以转换为 B)。负责发送消息的类,包含多个(模板化,因为消息没有基类)方法,使用函数重载为两种寻址类型重复。

class Sender{
public:
// old API
template<typename TReq>
send(const A&target, TReq req){send(target, make_request{req});}

// old API
template<typename TReq>
send(const B&target, TReq req){sendB(target, make_request{req});}

protected:
// done for mocking/testing purpose only
virtual send(const A&target, MessageProxy message);
virtual sendB(const A&target, MessageProxy message);
};

寻址 A 和 B 可由用户互换完成(他们不在乎这是 A 还是 B 类型的地址)为了与 google mock 玩得很好,我需要为重载方法提供不同的名称(我可以在 mock 中做到这一点,但决定在这里以不同的方式称呼它们,没有区别)

我要解决的问题很简单。提供单个虚拟发送方法,它将采用对地址类型 A 或 B 的引用的“联合”(将其视为变体<A&,B&>),其使用方式与这些方法的模板版本相同,例如。

virtual send(const TargetProxy &target, MessageProxy message);

可以使用的

EXPECT_CALL(mock, send(Eq(A{}), Message{}))...
EXPECT_CALL(mock, send(Eq(B{}), OtherMessage{}))...

携带 A& 或 B& (TargetProxy) 的类型应该持有对 A OR 到 B 的 const 引用,并且应该只用于将 A 或 B 从模板发送传递到虚拟发送,但我没有找到一个简单的解决方案

标签: c++referencevariant

解决方案


缺少很多样板,但 PoC 可能是这样的:

#include <utility>
#include <cassert>
#include <iostream>

struct A {};
struct B {};

struct EitherRef : private std::pair<A*, B*>
{
    EitherRef(A& a)
    : std::pair<A*, B*>(std::addressof(a), nullptr){};
    EitherRef(B& b)
    : std::pair<A*, B*>(nullptr, std::addressof(b)){};

    bool hasA() const {return this->first!=nullptr;}
    bool hasB() const {return this->second;}
    operator A&() { assert (this->first);return *this->first; }
    operator B&() { assert (this->second);return *this->second; }

};

template <typename Func>
void applyVisitor(EitherRef e, Func f)
{
    if (e.hasA()) {
        f(static_cast<A&>(e));
    } else if (e.hasB()) {
        f(static_cast<B&>(e));
    }
}

void f(const EitherRef& r)
{
    struct {
        void operator()(A&) {
            std::cout <<"A\n";
        }
        void operator()(B&) {
            std::cout <<"B\n";
        }
    } v;
    applyVisitor(r, v);
}

int main(int, char*[])
{
    A a1;
    B b1;
    EitherRef ra{a1};
    EitherRef rb{b1};
    f(ra);
    f(rb);

    return 0;
}


推荐阅读