如何实现一堆类似的类

时间:2016-04-26 16:09:34

标签: c++ boost crtp

我的任务是定义由不同数量的属性组成的设备的规范类。例如,Device1规范包含Property1,Property2。其他一些Device2仅包含Property1,DeviceX规范包含Property5,Property6等。

为了避免重复那些setProperty方法的类似实现,我决定将它们存储在不同的类中,并从中派生出一堆规范。

有许多非常相似的类包含使用CRTP惯用法的专用方法。 CRTP用于访问SPECIFICATION类的setParameter方法:

template<typename SPECIFICATION>
struct Property1
{
    void setProperty1( const double & Value)
    {
        static_cast<SPECIFICATION*>(this)->setParameter( "Property1", Value);
    }
};

template<typename SPECIFICATION>
struct Property2
{
    void setProperty2( const double & Value)
    {
        static_cast<SPECIFICATION*>(this)->setParameter( "Property2", Value);
    }
};

这些模板化的类然后用于CRTP习语:

template<typename DEVICE_TYPE>
class Device
{
public:
        class Specification;
};

template<>
class Device<DeviceTypeAAA>::Specification
        :   public Property1<Specification>,
            public Property2<Specification>
{
};

template<>
class Device<DeviceTypeBBB>::Specification
        :   public Property1<Specification>
{
};

template<>
class Device<DeviceTypeCCC>::Specification
        :   public Property2<Specification>
{
};

从上面的代码片段可以看出,Device的规范是使用所需属性的继承来“组装”的。所有设备都是Device :: Specification的专用类。

问题:由于实际上有很多“属性类”实现了“setProperty”方法和很多设备规范类,我很想知道是否有一些优雅的方法如何实现这一类相似的类更高的代码效率。我想到使用boost :: mpl :: vector与boost线性继承一起定义设备应该派生的所有属性的列表......也许我正在遵循完全错误的方向实现这一点。如果您愿意,请告诉我。

如果您对如何优化实施有一些了解,我会很高兴。非常感谢任何愿意提供帮助的人!

1 个答案:

答案 0 :(得分:0)

下面的实现使用variadics模板,但会导致可能很长的继承堆栈,但它应该不是问题。

除此之外,它完成了这项工作,将规范的定义减少为一个带有属性列表的继承声明。

它在GCC 4.7(C ++ 11)和更多版本以及clang 3.8上编译并运行良好。

#include <iostream>
#include <string>

template<typename SPECIFICATION>
struct Property1
{
    void setProperty1( const double & Value)
    {
        static_cast<SPECIFICATION*>(this)->setParameter( "Property1", Value);
    }
};

template<typename SPECIFICATION>
struct Property2
{
    void setProperty2( const double & Value)
    {
        static_cast<SPECIFICATION*>(this)->setParameter( "Property2", Value);
    }
};

template<typename SPECIFICATION, template<typename> class ... PROPERTIES>
struct Properties; // primary-template

template <typename SPECIFICATION, 
          template<typename> class PROPERTY, 
          template<typename> class ... PROPERTIES>
struct Properties<SPECIFICATION, PROPERTY, PROPERTIES...> : 
       PROPERTY<SPECIFICATION>, 
       Properties<SPECIFICATION, PROPERTIES...>{}; // head specialisation 

template <typename SPECIFICATION, 
          template<typename> class PROPERTY>
struct Properties<SPECIFICATION, PROPERTY> : 
       PROPERTY<SPECIFICATION>{}; // tail specisalization

template<typename DEVICE_TYPE>
class Device
{
public:
        class Specification;
};

struct DeviceTypeAAA{};
struct DeviceTypeBBB{};
struct DeviceTypeCCC{};

template<>
class Device<DeviceTypeAAA>::Specification
        :   public Properties<Specification, Property1, Property2>
{
    public:
    void setParameter(const std::string &name, double value){
        std::cout << "DeviceTypeAAA: "  << name << " = " << value << "\n";
    }
};

template<>
class Device<DeviceTypeBBB>::Specification
        :   public Properties<Specification, Property1>
{
    public:
    void setParameter(const std::string &name, double value){
        std::cout << "DeviceTypeBBB: "  << name << " = " << value << "\n";
    }
};

template<>
class Device<DeviceTypeCCC>::Specification
        :   public Properties<Specification, Property2>
{
    public:
    void setParameter(const std::string &name, double value){
        std::cout << "DeviceTypeCCC : "  << name << " = " << value << "\n";
    }
};


int main()
{
  Device<DeviceTypeAAA>::Specification a{};
  Device<DeviceTypeBBB>::Specification b{};
  Device<DeviceTypeCCC>::Specification c{};

  a.setProperty1(2.);
  a.setProperty2(2.);

  b.setProperty1(2.);
  b.setProperty2(2.); // compiler error, no member setProperty2

  c.setProperty1(2.);  // compiler error setProperty1
  c.setProperty2(2.);


}