带运算符|=的constexpr

constexpr with operator|=

本文关键字:constexpr 运算符      更新时间:2023-10-16

我尝试编写一个函数,该函数使用C++0x constexpr返回一个只包含输入集最高位的整数。

constexpr inline uint64_t
get_highest_bit(uint64_t p)
{
  return 
     (p|=(p>>1)),
     (p|=(p>>2)),
     (p|=(p>>4)),
     (p|=(p>>8)),
     (p|=(p>>16)),
     (p|=(p>>32)),
     (p-(p>>1));
}

这会导致使用gcc 4.6.1的编译时失败。

error: expression ‘(p <unknown operator> ((p >> 1) | p))’ is not a constant-expression

请注意,它在没有constexpr关键字的情况下工作。

我的问题是:

为什么这不起作用?我可以看到运算符|=不是constexpr,但它对内置类型有意义吗?

有没有一种简单的方法可以把这个函数写成constexpr?我希望它在运行时合理高效,并且我有点关心可读性。

(没有在GCC上测试,因为我没有4.6,但我已经验证了算法是正确的。(

若要使用constexpr,您必须没有分配。因此,您通常必须使用递归以函数形式编写:

#include <cstdint>
#include <climits>
constexpr inline uint64_t highestBit(uint64_t p, int n = 1) {
    return n < sizeof(p)*CHAR_BIT ? highestBit(p | p >> n, n * 2) : p - (p >> 1);
}
int main() {
    static_assert(highestBit(7) == 4);
    static_assert(highestBit(5) == 4);
    static_assert(highestBit(0x381283) == 0x200000);
    return 0;
}

您可以检查C++0x§[expr.const]/2,了解哪些表达式不能在constexpr函数中使用。特别是倒数第二项是"作业或复合作业"。

constexpr inline uint64_t highestBit(uint64_t p)
{
    return (p & (p-1))? highestBit(p & (p-1)): p;
}

每一级递归都会清除设置的最右边的位,当最后一位被清除时,只剩下最高的位,所以它会被返回。