Object 类模板实例仅限于预定义的对象

Object 类模板实例仅限于预定义的对象,object,templates,c++14,template-specialization,predefined-variables,Object,Templates,C++14,Template Specialization,Predefined Variables,我想要一个类模板模板形状,其中模板参数N表示形状的维度。预定义的形状的数量应该有限,例如形状正方形、形状立方体和形状球体。将来我可能会添加更多预定义的Shapes 我只希望Shape对象可以构造为任何预定义的Shapes。由于这些预定义的Shapes的属性始终保持不变,因此最好只存储一次,并让新的Shape对象引用它们 目前,我有以下实现: // Flag for the possible shapes enum class Tag { SPHERE, CUBE, SQU

我想要一个类模板
模板形状
,其中模板参数
N
表示
形状
的维度。预定义的
形状
的数量应该有限,例如
形状正方形
形状立方体
形状球体
。将来我可能会添加更多预定义的
Shape
s

我只希望
Shape
对象可以构造为任何预定义的
Shape
s。由于这些预定义的
Shape
s的属性始终保持不变,因此最好只存储一次,并让新的
Shape
对象引用它们

目前,我有以下实现:

// Flag for the possible shapes
enum class Tag
{
    SPHERE,
    CUBE,
    SQUARE
};

template<std::size_t N>
class Shape
{
public:
    // Predefined shapes.
    static const Shape<3> SPHERE;
    static const Shape<3> CUBE;
    static const Shape<2> SQUARE;
    // Information stored about the given shapes
    const Tag tag; // tag specifying the shape
    const double v; // Shape volume/area
    const std::array<double, 2*N> surrounding_box; // Storing intervals for a surrounding box
    //... Some other information that depends on template parameter N
private:
    // Private constructor. This prevents other, unintended shapes from being created
    Shape(Tag tag, double v, const std::array<double, 2*N> surrounding_box):
            tag{tag}, v {v}, surrounding_box {surrounding_box} {};
};

// Initialization of predefined shape: SPHERE
template<std::size_t N>
const Shape<3> Shape<N>::SPHERE(Tag::SPHERE, 3.0,{{0.0,2.7,0.0,2.7,0.0,2.7}});

// Initialization of predefined shape: CUBE
template<std::size_t N>
const Shape<3> Shape<N>::CUBE(Tag::CUBE, 1.0,{{0.0,1.0,0.0,1.0,0.0,1.0}});

// Initialization of predefined shape: SQUARE
template<std::size_t N>
const Shape<2> Shape<N>::SQUARE(Tag::SQUARE, 1.0,{{0.0,1.0,0.0,1.0}});
//可能形状的标志
枚举类标记
{
球
立方体
广场
};
样板
阶级形态
{
公众:
//预定义的形状。
静态常形球;
静态恒形立方体;
静态恒形正方形;
//存储的有关给定形状的信息
const Tag Tag;//指定形状的标记
常数双v;//形状体积/面积
const std::array around_box;//存储周围框的间隔
//…依赖于模板参数N的其他一些信息
私人:
//私有构造函数。这可以防止创建其他非预期形状
形状(标签、双v、常数标准::环绕在盒子周围的阵列):
tag{tag},v{v},包围盒{包围盒}{};
};
//预定义形状的初始化:球体
样板
const-Shape::SPHERE(标记::SPHERE,3.0,{{0.0,2.7,0.0,2.7,0.0,2.7});
//预定义形状的初始化:立方体
样板
const-Shape-Shape::CUBE(标记::CUBE,1.0,{{0.0,1.0,0.0,1.0,0.0,1.0});
//预定义形状的初始化:方形
样板
constshape::SQUARE(标记::SQUARE,1.0,{0.0,1.0,0.0,1.0});
此实现有几个问题:

  • Shape
    的每个实例都包含所有预定义的
    Shape
    s(如的注释中所指出)
  • 在创建的每个
    Shape
    实例之前,将复制预定义的
    Shape
    s的内容
  • 即使是
    形状
    对象也包含
    形状正方形
我想知道实现上述目标的更好的设计模式是什么。
我正在考虑使用
标记作为构造函数参数,并使用某种工厂。但是,由于模板的复杂性以及我只希望预定义的
形状可以构造的事实,我在获得正确的实现细节方面遇到了问题。

工厂模式是您所需要的。它将实例的创建委托给另一个类

实现它有多种方法,您可以根据问题的复杂性选择抽象级别

这里有一个基本的例子

template<std::size_t N>
class Shape
{
    friend class ShapeFactory;
public:
    // Information stored about the given shapes
    const Tag tag; // tag specifying the shape
    const double v; // Shape volume/area
    const std::array<double, 2*N> surrounding_box; // Storing intervals for a surrounding box
    //... Some other information that depends on template parameter N
private:
    // Private constructor. This prevents other, unintended shapes from being created
    Shape(Tag tag, double v, const std::array<double, 2*N> surrounding_box):
            tag{tag}, v {v}, surrounding_box {surrounding_box} {};
};

class ShapeFactory
{
public:
    // return value optimization
    static Shape<3> createSphere()
    {
        return Shape<3>(Tag::SPHERE, 3.0,{{0.0,2.7,0.0,2.7,0.0,2.7}});
    }

    static Shape<3> createCube()
    {
        return Shape<3>(Tag::CUBE, 1.0,{{0.0,1.0,0.0,1.0,0.0,1.0}});
    }

    static Shape<2> createSquare()
    {
        return Shape<2>(Tag::SQUARE, 1.0,{{0.0,1.0,0.0,1.0}});
    }
};
模板
阶级形态
{
友元类形状因子;
公众:
//存储的有关给定形状的信息
const Tag Tag;//指定形状的标记
常数双v;//形状体积/面积
const std::array around_box;//存储周围框的间隔
//…依赖于模板参数N的其他一些信息
私人:
//私有构造函数。这可以防止创建其他非预期形状
形状(标签、双v、常数标准::环绕在盒子周围的阵列):
tag{tag},v{v},包围盒{包围盒}{};
};
类形状因子
{
公众:
//收益值优化
静态形状createSphere()
{
返回形状(标记::SPHERE,3.0,{{0.0,2.7,0.0,2.7,0.0,2.7});
}
静态形状createCube()
{
返回形状(标记::立方体,1.0,{{0.0,1.0,0.0,1.0,0.0,1.0});
}
静态形状createSquare()
{
返回形状(标记::SQUARE,1.0,{{0.0,1.0,0.0,1.0});
}
};
因为这些预定义形状的属性保持不变 时间,最好只存储一次,并且 新的形状对象引用它们

如果您严格地想要使用这种方法,您可以参考原型模式