Search code examples
c++templatesleading-zero

How to make a countl_zero() but for any type?


I use in my project such a function for counting leading zeros, the aim for it is to work with any non container type and to return a constant expression, so that I could use it's results for other templates.

template <typename T>
consteval int CountLeadingZeros(const T& DATA) {
    T MASK{ 1 };
    int BITSN{ sizeof(T) * CHAR_BIT },
        LEADINGN{ 0 };
    MASK <<= BITSN - 1;
    for (int I = BITSN; I > 0; I--, LEADINGN++, MASK >>= 1) {
        if (DATA & MASK) {
            break;
        }
    }
    return LEADINGN;
}

But of cause it doesn't return a real const expression. If you'll try to use it, there will be an error:

    constexpr int value = CountLeadingZeros <const int> (100);

Error:

E3133 call to consteval function "fsm::CountLeadingZeros(const T &DATA) [with T=const int]" did not produce a valid constant expression

On the other hand C++20 countl_zero() works perfect and returns constexpr. But it can not work with anything except uint8_t.

Help me please to fight and win this E3133 error. How could I make my function working in compile time?


Solution

  • Don't pass const int as the template argument. Replace it with just int. Currently, MASK gets declared as const int MASK = 1, and then you try to modify it, which obviously doesn't work. Otherwise, the function should be constant-evaluatable