封装了许多类型的Datastructure <t>并公开了它们的所有功能

时间:2017-05-11 11:33:20

标签: c++ data-structures adapter c++14 encapsulation

我有6种datastructure<T>

所有这些都包含10-20个常用功能(紫色),例如addFirst()

但是,某些数据结构有自己的0-5独特功能(粉红色) 例如,只有MyArray<T>具有函数addManual(T,int) 在极少数情况下,一些不同类型的数据结构支持一些相同的特殊功能。

enter image description here
(实际案例表的复杂程度要高出约10倍。)

这是一个简短的片段: -

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支持这些功能?

以下是我的三个糟糕解决方案: -

  1. 为每种类型的数据结构创建许多适配器类,例如: AdapterMyArray<T,I>AdapterMyGrid3D<T,I>

  2. 通过继承改进第一个解决方案,例如:来自AdapterMyArray<T,I>的{​​{1}}和AdapterMyGrid3D<T,I>

  3. 检查AdapterBase<T,I>的类型并使用MyX启用这些特殊功能的实例化。

  4. 我觉得我的所有解决方案都是 手动 ,这会导致一些可维护性问题。

    编辑: Yakk的解决方案很好,但我仍然怀疑是否有更好的解决方案。

1 个答案:

答案 0 :(得分:1)

CRTP。

拥有Adapter_addFirst Adapter_addManual等CRTP助手。他们使用CRTP访问database<T>并实现他们的一个(或一组)功能。

Adapter通过traits类助手查询databasedatabase<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或同等内容。