Search code examples
c++metaprogramminggeneric-programming

template metaprogramming - g++ eats it, clang does not


Any way to get both compilers to be happy?

for this:

template<short value>
struct static_signbits
{
    enum { result = (!!(value & 0x8000) == !!(value & 0x4000)) ? (static_signbits<short(value << 1)>::result + 1) : 0 };
};

template<>
struct static_signbits<0>
{
    enum
    {
        result = 15
    };
};

clang gives me:

error: non-type template argument is not a constant expression
        enum { result = (!!(value & 0x8000) == !!(value & 0x4000)) ? (static_signbits<short(value << 1)>::result + 1) : 0 };
                                                                                      ^~~~~~~~~~~~~~~~~  

It is apparently unhappy about the cast to the short?

Apparently, I could use constexpr instead, but I also require backward compatibility to C++98


Solution

  • This is because clang does not support negative << n in constant expressions. Simply shift unsigned values instead:

    template<short value>
    struct static_signbits
    {
        enum { result = (!!(value & 0x8000) == !!(value & 0x4000)) ? (static_signbits<(short)((unsigned)value << 1)>::result + 1) : 0 };
    };
    

    clang is correct, since left shifting a negative is undefined behavior.