【问题标题】:C++ struct field name and types from variadic template来自可变参数模板的 C++ 结构字段名称和类型
【发布时间】:2021-03-10 11:46:53
【问题描述】:

嘿,我正在尝试用 c++ 实现Color 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 静态保留,因为我不希望我的空间组件增加大小(想象一下,如果我这样做,我的 ram 中 4096x4096 图像的大小将是多少)。

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

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;
    }
};

我停在这两个上,因为我意识到我需要为所有空间编写所有运算符重载逻辑,这是一项巨大的工作。我需要以某种方式在一个结构struct Space 中实现运算符重载,并从中派生所有其他结构。注意我不能有任何虚拟方法,因为任何指向vtable 的指针都会增加sizeof(Space) 并且会引发我已经提到的问题。我想我需要模板元编程之类的东西来做到这一点(使用宏是我的最后选择) 或使用CRTP 之类的技术,作为草稿,我认为我的 Space 实现可以是这样的。

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

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

【问题讨论】:

  • 您可能正在寻找std::tuple
  • 或者std::array,如果所有颜色都属于同一类型。
  • @IgorTandetnik 是的,可能是这样,但是迭代一个元组并将一个元素添加到另一个元素的时间效率低于仅添加 a += otherSpace.a 。我想我同时需要速度和内存:D
  • @IgorTandetnik 它已经过测试)))
  • @max66 将范围从空间组件中拆分出来并定义了特定空间中每个组件的所有范围可能有助于使用std::arrays 实现这一点

标签: c++ templates colors metaprogramming variadic-templates


【解决方案1】:

我认为如果所有组件都具有相同的类型是可能的。 我们可以这样声明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&lt;ComponentImpl&gt;。 而在operator+ 内部,只需遍历这个数组并对所有组件求和。

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

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

【讨论】:

  • 至此基本实现,我们需要更新Space的构造函数,使其能够像RGB space{val1, val2, val3}一样创建,并添加一些其他实用功能。
  • 要获得恒定时间get(),您可以使用std::tuple 方法(具有继承和static_cast),但这里的索引不是std::tuple,而是char ('r'/'g'/ ..).
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多