来自可变参数模板的 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;
}
};
通过这个逻辑,我可以创建我想要的任何类型的颜色组件,并且它不会退出它的范围(参见实现)。请注意,我保持 MIN
和 MAX
静态,因为我不希望我的 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
嘿,我正在尝试用 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;
}
};
通过这个逻辑,我可以创建我想要的任何类型的颜色组件,并且它不会退出它的范围(参见实现)。请注意,我保持 MIN
和 MAX
静态,因为我不希望我的 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