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



我有一个既没有c++ 17 (c++ 14 ATM)特性也没有boost的环境。

目前我有一个类负责在我们的领域的服务之间发送消息,这个类使用多种类型的寻址(两种类型都是非平凡的),其中一种可以转换为另一种(假设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中这样做,但决定在这里以不同的方式调用它们,没有区别)

我想解决的问题很简单。提供一个虚拟发送方法,它将接受一个"union";地址类型A或B的引用(可以将其视为变体<A&,>),可以与这些方法的模板化版本一样使用,例如。
virtual send(const TargetProxy &target, MessageProxy message);

可以使用

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

带A&或B&(TargetProxy)应该持有一个const引用到A或B,应该只用于传递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 <<"An";
}
void operator()(B&) {
std::cout <<"Bn";
}
} v;
applyVisitor(r, v);
}
int main(int, char*[])
{
A a1;
B b1;
EitherRef ra{a1};
EitherRef rb{b1};
f(ra);
f(rb);
return 0;
}