为模板类提供多个可供选择的模型

Providing multiple models for a template class to choose from

本文关键字:选择 模型      更新时间:2023-10-16

我目前正在使用模板来构建一个颜色类。我之所以使用模板,是因为可以使用不同的颜色空间或颜色模型来定义和存储颜色。

所以基本上,我想出了一个类,它将颜色模型类作为模板参数并从中继承,以便访问特定于模型的方法,如RGB模型的red(), green()blue(),或HSV模型的hue(), saturation()value()。我还写了一些模型类,以及一些方便的颜色类型和模型转换函数。

template <typename T>
class Color : public T {
public:
    typedef T Model;
    using T::T;
    // This is meant to convert colors with different models
    template <typename U>
    explicit Color(const Color<U>& c);
};
class RGB {
public:
    static constexpr auto name = "RGB";
    RGB() = default;
    RGB(unsigned int argb);
    RGB(unsigned int r, unsigned int g, unsigned int b, unsigned int a = 0xFF);
    RGB lighter(double factor = 1.2) const;
    RGB negative() const;
    RGB greyscale() const;
    unsigned int argb() const;
    unsigned int red() const;
    unsigned int green() const;
    unsigned int blue() const;
    unsigned int alpha() const;
private:
    unsigned int m_argb;
};
class HSV {
public:
    static constexpr auto name = "HSV";
    HSV() = default;
    HSV(unsigned int h, unsigned int s, unsigned int v, unsigned int a = 0xFF);
    HSV lighter(double factor = 1.2) const;
    HSV complementary() const;
    HSV greyscale() const;
    unsigned int hue() const;
    unsigned int saturation() const;
    unsigned int value() const;
    unsigned int alpha() const;
private:
    unsigned int m_h, m_s, m_v, m_a;
};
typedef Color<RGB> RGBColor;
typedef Color<HSV> HSVColor;
template<typename From, typename To>
To ColorModelConverter(From model);
template<>
RGB ColorModelConverter<HSV, RGB>(HSV model);
template<>
HSV ColorModelConverter<RGB, HSV>(RGB model);

一开始这似乎是个好主意。然而,多重问题出现了,首先是整个事情看起来很丑陋,注定要失败。

事实上,我有两个主要问题,首先是如下:如何使模型的方法返回颜色而不是模型(他们自己的类型)?

Color<RGB> greyscale() const;
// ... instead of ...
RGB greyscale() const;

另一个问题在于不同型号的颜色之间的转换:

template <typename U>
explicit Color(const Color<U>& c);

我最初计划在这个构造函数中使用模型转换函数,但我无法设置它。

这种设计背后的思想是能够创建新的颜色模型,并使用与现有颜色模型之间的适当转换器,并将它们与color类一起使用(该类具有模型类型的typedef和通用转换构造函数)。[edit]为了创建新的颜色模型,不需要(也不应该)修改任何现有的类(模型或颜色类),但可能需要编写相应的转换器。[编辑]

所以我的问题是:我的设计是否有可能修复,基本上,一个好的设计(修复后)?如果没有,我该怎么做才能拥有与我指定的相同的功能呢?

从你的一个评论:

没有代码不应该关心所使用的模型。

我想这就是问题的关键所在。

如果没有模型独立的Color客户端代码,那么模板和面向对象都没有意义。

你基本上已经创建了两个完全独立的类,碰巧它们的名字中有尖括号。只需创建两个完全独立的非模板类RgbColorHsvColor。这会使你的整个代码更清晰。

的主要好处是有一个转换构造函数,而不是函数,如果添加新模型,则无需修改现有模型添加转换器).

我不认为这会带来任何真正的好处,因为您仍然需要显式地实现从模型X到模型y的每一次转换。在任何情况下都没有真正的自动化。

更简洁的解决方案是编写非成员非友元转换函数:
RgbColor ToRgb(HsvColor const &color);
HsvColor ToHsv(RgbColor const &color);

Non-member - non-friend表示如果添加了新模型,不需要更改任何类。这进一步意味着所有的转换在客户端代码中都是清晰可见的,并且不太可能发生意外的不需要的转换。

另一个优点是支持单向转换。例如,您以后可能需要一个不支持alpha的RGB颜色类。RgbColorNoAlpha的实例应该转换为RgbColor,反之则不行。通过RgbColorNoAlpha ToRgbColorNoAlpha(RgbColor const &color)缺失,代码可以轻松地满足这一要求。

这种设计背后的思想是能够创建新的颜色模型,并使用与现有模型之间的适当转换器,并将它们与color类一起使用(该类具有模型类型的typedef和通用转换构造函数)。

这应该可以通过模板专门化实现。您可以为每个不同的颜色模型组合实现一个实例,或者实现一个通用模型,并在每个其他颜色模型中为其提供一个私有转换器。

考虑这种可能性:

struct HSV; //undefined
struct RGB; //undefined
template<class M> class color; //undefined
template<>
class color<RGB>
{
  //specific RGB implementations
};
template<>
class color<HSV>
{
  //specific HSV implementation
};

但是就你的设计而言,在RGC和HSV之间没有公共接口,因此将它们作为共同祖先意义不大。

如果在各种颜色的实现中没有共同的成员,你可以写哪种fn(color<M>)类型的函数?