我一直在研究奇怪的重复模板模式,以确定如何使用它来实现桥设计模式。
我的问题是将IBridgeConnector :: GetBridgeImpl方法连接到Bridge :: GetBridgeImpl方法,因为覆盖方法实际上是模板化的。
由于虚拟调度在这种情况下不起作用,将这些方法指向对方的最佳方法是什么?功能代表?对此有更好的模式吗?
应该怎么做?
感谢您的帮助!
我可以在没有shared_ptrs和OpenGL和DirectX调用的情况下实现最佳代码简化。 :)希望这对未来的人有用!
#include <string>
/********************************************************************/
class BridgePart
{
public:
BridgePart * OtherPart;
};
/********************************************************************/
// Connects a BridgeSource and a BridgeImplementation
class BridgeConnector
{
public:
static BridgeConnector * implementor;
// Need a way, (Function Delegates?) to point this method
// This method will loop until stack overflow.
template <typename ValueTemplateType>
BridgePart * GetBridgeImpl(ValueTemplateType * source)
{
return implementor->GetBridgeImpl<ValueTemplateType>(source);
}
};
BridgeConnector * BridgeConnector::implementor = nullptr;
/********************************************************************/
// Where the Magic is At, (CRTP)
template <typename BridgeImplementationTemplateType>
class Bridge : public BridgeConnector
{
public:
template <typename ValueTemplateType>
IBridgePart * GetBridgeImpl(IBridgePart * source)
{
// NOTE: This method never gets called.
// CRTP Magic Here to Semi-Specify Pure Virtual Methods
return static_cast<BridgeImplementationTemplateType>(this)
->GetBridgeImpl( (ValueTemplateType) source);
}
};
/********************************************************************/
class BridgeImplementation1 :
public Bridge<BridgeImplementation1>,
public BridgePart
{
public:
class CustomImpl : public BridgePart
{
public:
template <typename SourceTemplateType>
BridgePart(SourceTemplateType source){}
/* Does proprietary stuff. */
};
template <typename ValueTemplateType>
BridgePart * GetBridgeImpl(ValueTemplateType & source)
{
return new CustomImpl<ValueTemplateType>(source);
}
// Constructor
BridgeImplementation1()
{
}
};
/********************************************************************/
class BridgeSource1 : public BridgePart {};
class BridgeSource2 : public BridgePart {};
class Client
{
BridgeSource1 source1;
BridgeSource2 source2;
BridgeConnector * connector;
bool usingImpl1;
Client()
{
usingImpl1 = true; // from config file.
connector = new BridgeConnector();
connector->implementor = usingImpl1
? (BridgeConnector *) new BridgeImplementation1()
: nullptr; // (BridgeConnector *) new BridgeImplementation2();
// removed to shorten code.
}
void Init()
{
source1.OtherPart = connector->GetBridgeImpl<BridgeSource1>(& source1);
source2.OtherPart = connector->GetBridgeImpl<BridgeSource2>(& source2);
}
};
答案 0 :(得分:3)
当您在LoadDriver
函数中调用Client::Init
时,ValueTemplateType
模板参数为std::string*
,即指针。桥实现类BridgeImplementation1
和BridgeImplementation2
具有不获取指针的函数。因此,当编译器试图找到匹配的LoadDriver
函数时,它不会考虑采用非指针参数的函数,只考虑采用指针参数的函数。
您应该更改LoadDriver
和BridgeImplementation1
中的BridgeImplementation2
函数以获取指针参数。
答案 1 :(得分:3)
我认为你对CRTP有点误解。它不是虚拟调度的插件替代品。在您的情况下,IBridge没有虚拟调度,因此调用IBridge-&gt; LoadDriver将始终为您提供默认的基类实现,而不管底层的派生类。如果需要通用接口,则需要某种虚拟分派。 CRTP只是在不需要的情况下避免虚拟分派的一种方法,例如当基类成员函数调用其他虚函数时。
如果你想在你的情况下完全避免虚拟调度,你不能完全将客户端与Bridge分离,你需要在Bridge上模拟Client,这实际上并没有给你带来任何优于衍生的模板的优势。 / p>
这是拍摄你想做的事情。它假设您通过IBridge传递一些通用指针,Bridge使用CRTP解释并传递给BridgeImpl。显然,你已经放弃了对这一论点的所有类型安全的希望。
class IBridge {
virtual void LoadDriver(void *) = 0;
};
template <typename Impl>
class Bridge : public IBridge {
void LoadDriver(void * v) override {
static_cast<Impl*>(this)->LoadDriverImpl(*static_cast<Impl::arg_type *>(v));
}
};
class BridgeImpl : public Bridge<BridgeImpl> {
typedef std::string arg_type;
void LoadDriverImpl(const std::string & s){ /*...*/ }
};