我有6种datastructure<T>
。
所有这些都包含10-20个常用功能(紫色),例如addFirst()
。
但是,某些数据结构有自己的0-5独特功能(粉红色)
例如,只有MyArray<T>
具有函数addManual(T,int)
在极少数情况下,一些不同类型的数据结构支持一些相同的特殊功能。
这是一个简短的片段: -
class Vector3D{};
template<class T>class MyArray{
public: void addFirst(T t){/* some code */}
/* other add / remove / query function */
public: void addManual(T t,int internalIndex){/* some code */}
};
template<class T>class MyGrid3D{
public: void addFirst(T t){/*some code */}
/* other add / remove / query function */
public: void addSpecial(T t,Vector3D gridAddress){/* some code*/}
};
到目前为止效果很好。
现在,我希望通过提供界面Adapter<MyX,T,I>
使其更容易使用
我的库的用户可以分别识别内部存储类型T
和接口I
。
每当函数的参数(紫色/粉红色)具有类型I
时,我会将其转换为T
并在内部操纵它,就像它具有类型T
一样。
这是我的原型: -
template<template<class> class MyX,class T,class I>class Adapter{
private: T convert(I i){/* some logic */ return T();}
MyX<T> database;
public: void addFirst(I i){
database.addFirst(convert(i));
}
};
int main() {
Adapter<MyArray,int,std::string> adapter;
adapter.addFirst(std::string("5.0f"));
std::cout<<"compiled OK";
return 0;
}
效果很好( coliru demo ),但它不包括特殊功能(紫色),例如addManual()
或addSpecial()
。
什么是设计模式/ C ++魔术使Adapter
支持这些功能?
以下是我的三个糟糕解决方案: -
为每种类型的数据结构创建许多适配器类,例如: AdapterMyArray<T,I>
和AdapterMyGrid3D<T,I>
。
通过继承改进第一个解决方案,例如:来自AdapterMyArray<T,I>
的{{1}}和AdapterMyGrid3D<T,I>
。
检查AdapterBase<T,I>
的类型并使用MyX
启用这些特殊功能的实例化。
我觉得我的所有解决方案都是 手动 ,这会导致一些可维护性问题。
编辑: Yakk的解决方案很好,但我仍然怀疑是否有更好的解决方案。
答案 0 :(得分:1)
CRTP。
拥有Adapter_addFirst
Adapter_addManual
等CRTP助手。他们使用CRTP访问database<T>
并实现他们的一个(或一组)功能。
Adapter
通过traits类助手查询database
或database<T>
,以确定它应该(公开)从哪个CRTP Adapter_*
继承。
template<class D, class I>
class Adapter_addFirst {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
public:
void addFirst(I i){
self()->database.addFirst(self()->convert(i));
}
};
template<std::size_t I>
struct empty_t {};
template<template<class> class MyX,class T,class I>
class Adapter:
public std::conditional_t<true, Adapter_addFirst<Adapter<MyX, T, I>, I>, empty_t<0>>
{
friend struct Adapter_addFirst<Adapter<MyX, T, I>, I>;
private:
T convert(I i){/* some logic */ return T();}
MyX<T> database;
};
其中true
被替换为&#34的测试;我应该使用addFirst&#34;。
对每种方法重复。
Dispatch是静态的,方法只有在应用时才存在,一切都符合标准。
您可以测试&#34;我应该添加手动&#34;通过您的类型上的标签,类型特征,甚至是对std::declval<MyX<T>&>().addManual( std::declval<T const&>() )
的呼叫的SFINAE测试。对于SFINAE案例,请参阅can_apply或同等内容。