简体   繁体   中英

Is it possible to have a static constexpr member with type X of template class X?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM