I once had 4 classes for 4 different RGB implementations (rgb, rgba, rgbf32, rgbaf32). Each class had a member color, and the code worked perfectly fine:
struct rgb {
std::uint8_t r;
std::uint8_t g;
std::uint8_t b;
const static rgb red;
};
constexpr rgb rgb::red = rgb{ 255, 0, 0 };
int main() {
constexpr auto red = rgb::red;
}
I had 4 times the code length because of this, so I decided to combine them into one templated class:
#include <cstdint>
#include <type_traits>
#include <array>
template<bool f32, bool alpha>
using rgb_content =
std::conditional_t<(!f32 && !alpha), std::array<std::uint8_t, 3>,
std::conditional_t<(!f32 && alpha), std::array<std::uint8_t, 4>,
std::conditional_t<( f32 && !alpha), std::array<float, 3>,
std::array<float, 4>>>>;
template<bool f32, bool alpha>
struct rgb {
rgb_content<f32, alpha> color;
constexpr static auto get_red() {
return rgb { f32 ? 1 : 255, 0, 0 };
}
const static rgb<f32, alpha> red;
};
template<bool f32, bool alpha>
const rgb<f32, alpha> rgb<f32, alpha>::red = rgb<f32, alpha>::get_red();
int main() {
constexpr auto red = rgb<0, 0>::red;
}
I no longer get the static member red
to work with this template class ( godbolt ):
error C2131: expression did not evaluate to a constant
I tried switching around constexpr
and other keywords, but no success. The only solution I found was naming all possibilities:
constexpr rgb<0, 0> rgb<0, 0>::red = rgb<0, 0>::get_red();
constexpr rgb<0, 1> rgb<0, 1>::red = rgb<0, 1>::get_red();
constexpr rgb<1, 0> rgb<1, 0>::red = rgb<1, 0>::get_red();
constexpr rgb<1, 1> rgb<1, 1>::red = rgb<1, 1>::get_red();
int main() {
using u8 = std::uint8_t;
static_assert(rgb<0, 0>::red.color == std::array{(u8)255u, (u8)0u, (u8)0u});
static_assert(rgb<0, 1>::red.color == std::array{(u8)255u, (u8)0u, (u8)0u, (u8)0u});
static_assert(rgb<1, 0>::red.color == std::array{1.0f, 0.0f, 0.0f});
static_assert(rgb<1, 1>::red.color == std::array{1.0f, 0.0f, 0.0f, 0.0f});
}
but this only compiles with MSVC (see here ) and it's pretty unmaintanable.
Is this even possible to implement? Do I have to use constexpr static
member functions like red()
instead?
constexpr auto red = rgb<0, 0>::red;
rgb<0,0>::red
is not a constexpr
value, this doesn't work.
This compiles for me, with gcc 12:
template<bool f32, bool alpha>
struct rgb {
rgb_content<f32, alpha> color;
constexpr static auto get_red() {
return rgb { f32 ? 1 : 255, 0, 0 };
}
constexpr static rgb<f32, alpha> red=get_red();
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.