来自可变参数模板的 C++ 结构字段名称和类型

C++ struct field name and types from variadic template

嘿,我正在尝试用 C++ 实现 Color space 逻辑。 正如您可能看到的,每种颜色 space 都有其独特的颜色组件及其独特的范围和名称,因此我尝试先实现一个 space 组件逻辑。

template<typename T, T min, T max>
struct SpaceComponent {
    static constexpr T MIN = min;
    static constexpr T MAX = max;
    T value;

    SpaceComponent() = default;

    SpaceComponent(T value) : value(static_cast<T>(value)) {
    }

    operator T() const {
        return value > MAX ? MAX : value < MIN ? MIN : value;
    }

    operator SpaceComponent<T, MIN, MAX>() const {
        return SpaceComponent<T, MIN, MAX>(static_cast<T>(value));
    }

    inline bool operator==(const SpaceComponent &other) const {
        return value == other.value;
    }

    inline bool operator!=(const SpaceComponent &other) const {
        return !(*this == other);
    }

    inline bool operator>(const SpaceComponent &other) const {
        return value > other.value;
    }

    inline bool operator<(const SpaceComponent &other) const {
        return !(*this > other) && *this != other;
    }

    inline bool operator>=(const SpaceComponent &other) const {
        return !(*this < other);
    }

    inline bool operator<=(const SpaceComponent &other) const {
        return !(*this > other);
    }

    inline SpaceComponent &operator=(const T &elem) {
        if (value == elem) {
            return *this;
        }
        value = static_cast<T>(elem);
        return *this;
    }

    inline SpaceComponent &operator=(const SpaceComponent &other) {
        if (*this == other) {
            return *this;
        }
        *this = other.value;
        return *this;
    }

    inline SpaceComponent &operator++() {
        *this = static_cast<T>(++value);
        return *this;
    }

    inline SpaceComponent &operator--() {
        *this = static_cast<T>(--value);
        return *this;
    }

    inline SpaceComponent operator+(const T &elem) const {
        SpaceComponent result;
        result = static_cast<T>(value + elem);
        return result;
    }

    inline SpaceComponent operator-(const T &elem) const {
        SpaceComponent result;
        result = static_cast<T>(value - elem);
        return result;
    }

    inline SpaceComponent operator*(const T &elem) const {
        SpaceComponent result;
        result = static_cast<T>(value * elem);
        return result;
    }

    inline SpaceComponent operator/(const T &elem) const {
        SpaceComponent result;
        result = static_cast<T>(value / elem);
        return result;
    }

    inline SpaceComponent operator+(const SpaceComponent &other) const {
        SpaceComponent result;
        result = static_cast<T>(value + other.value);
        return result;
    }

    inline SpaceComponent operator-(const SpaceComponent &other) const {
        SpaceComponent result;
        result = static_cast<T>(value - other.value);
        return result;
    }

    inline SpaceComponent operator*(const SpaceComponent &other) const {
        SpaceComponent result;
        result = static_cast<T>(value * other.value);
        return result;
    }

    inline SpaceComponent operator/(const SpaceComponent &other) const {
        SpaceComponent result;
        result = static_cast<T>(value / other.value);
        return result;
    }

    inline SpaceComponent operator+=(const T &elem) {
        *this = *this + elem;
        return *this;
    }

    inline SpaceComponent operator-=(const T &elem) {
        *this = *this - elem;
        return *this;
    }

    inline SpaceComponent operator*=(const T &elem) {
        *this = *this * elem;
        return *this;
    }

    inline SpaceComponent operator/=(const T &elem) {
        *this = *this / elem;
        return *this;
    }

    inline SpaceComponent &operator+=(const SpaceComponent &other) {
        *this = *this + other;
        return *this;
    }

    inline SpaceComponent &operator-=(const SpaceComponent &other) {
        *this = *this - other;
        return *this;
    }

    inline SpaceComponent &operator*=(const SpaceComponent &other) {
        *this = *this * other;
        return *this;
    }

    inline SpaceComponent &operator/=(const SpaceComponent &other) {
        *this = *this / other;
        return *this;
    }


};

通过这个逻辑,我可以创建我想要的任何类型的颜色组件,并且它不会退出它的范围(参见实现)。请注意,我保持 MINMAX 静态,因为我不希望我的 space 组件增加大小(想象一下如果我这样做,我的 ram 中 4096x4096 图像的大小是多少).

然后我尝试实现不同的 space 颜色

struct RGB {
    SpaceComponent<unsigned char, 0, 255> r;
    SpaceComponent<unsigned char, 0, 255> g;
    SpaceComponent<unsigned char, 0, 255> b;

    inline RGB operator+(const RGB &other) {
        RGB rgb;
        rgb.r = r + other.r;
        rgb.g = g + other.g;
        rgb.b = b + other.b;
        return rgb;
    }
};

struct ARGB {
    SpaceComponent<unsigned char, 0, 255> a;
    SpaceComponent<unsigned char, 0, 255> r;
    SpaceComponent<unsigned char, 0, 255> g;
    SpaceComponent<unsigned char, 0, 255> b;

    inline ARGB operator+(const ARGB &other) {
        ARGB argb;
        argb.a = a + other.a;
        argb.r = r + other.r;
        argb.g = g + other.g;
        argb.b = b + other.b;
        return argb;
    }
};

我在这两个地方停了下来,因为我意识到我需要为所有 space 编写所有运算符重载逻辑,这是一项艰巨的工作。我需要以某种方式在一个结构 struct Space 中实现运算符重载并从中派生所有其他结构。请注意,我不能有任何虚拟方法,因为任何指向 vtable 的指针都会增加 sizeof(Space) 并且会引发我已经 mentioned.I 认为我需要类似模板元编程的问题来执行此操作(使用宏是我最后的选择)或使用像 CRTP 这样的技术作为草稿,我认为我的 Space 实现看起来像这样。

using RGB = Space<SpaceComponent<unsigned char,0,255> r,SpaceComponent<unsigned char,0,255> g,SpaceComponent<unsigned char,0,255> b>;

我知道这样写是违法的,但我能有一个语法至少和这个差不多的结构吗?提前致谢。

我认为如果所有组件都具有相同的类型是可能的。 我们可以这样声明 Space

template <typename T, typename ...Components>
struct Space {...}

并使用如下语法:

Space<unsigned char, Component<'r'>, Component<'g'>, Component<'b'>>;

哪里

template <char Id>
struct Component{...} // Component is just wrapper for ComponentImpl (for creation, to not duplicate types every time)

template <typename T> // your `SpaceComponent`
struct ComponentImpl{...} 

然后在Space里面我们可以使用constexpr函数来填充std::array<ComponentImpl>。 在 operator+ 中,只需遍历此数组并对所有组件求和。

另外,我们(可能)不必存储 T min、T max,我们可以使用 std::numeric_limits 来获取它们。

更新:
我写了一些原型,看看:https://godbolt.org/z/oEThae