在 C++ 中存储视图类型的引用变体

Storing an variant of references for a view type in C++

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

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

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,我需要为它们提供不同的名称重载方法(我可以在模拟中这样做,但决定在这里以不同的方式调用它们,没有区别)

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

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 或 B 的 const 引用,并且应该仅用于将 A 或 B 从模板化发送传递到虚拟发送,但我没有想出一个简单的方法这个

的解决方案

缺少很多样板文件,但 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;
}