在constexpr函数中有效调用_BitScanReverse或__builtin_clz的方法?

时间:2017-10-09 20:55:57

标签: c++ visual-c++ g++ constexpr intrinsics

似乎_BitScanReverse,尽管是一个内在的而不是一个真正的函数,但不能在Visual C ++中的constexpr函数中调用。我知道我可以用更慢的方式自己实现这个操作,这对于它在编译时进行评估的情况会很好,但不幸的是它不会这样做。对于在运行时进行评估的情况,它只是1个时钟周期的单CPU指令(BSR)。我还没有尝试过GCC / Clang中的__builtin_clz,但它可能会或可能不会出现同样的问题,我希望这些代码可以在主要的编译器中运行,(对于非GCC,非缓慢回退) -Clang,非VC编译器。)

思想/问题:

在编译时进行评估时,是否有一种简单的方法可以让函数使用一个代码块,这样它就可以是constexpr-safe,并且可以为运行时提供不同的代码块,这样它就可以很快? (如果是这样,这也与我的其他一些问题有关。)

或者,有没有办法欺骗编译器能够为constexpr代码评估_BitScanReverse?

附带问题:

有没有计划最终将其添加到C ++标准?他们已经添加了std :: log2和std :: ilogb,但这些都是通过浮点数而不是只做一个BSR(或者是ARM芯片上的CLZ和减法)。

2 个答案:

答案 0 :(得分:1)

对于 C++20,您可以使用 std::bit_width 和其他形式的 <bit> 标头

template< class T >
constexpr T bit_width(T x) noexcept;
#include <bit>
#include <bitset>
#include <iostream>
#include <array>

using BitArray = std::array<unsigned, 8>;

constexpr BitArray Bits() {
    BitArray bits;
    for (unsigned x{0}; x != 8; ++x)
      bits[x] = std::bit_width(x);
    return bits;
}

auto main() -> int {
    constexpr BitArray bits = Bits();

    for (unsigned x{0}; x != 8; ++x) {
        std::cout
            << "bit_width( "
            << std::bitset<4>{x} << " ) = "
            << bits[x] << " "
            << std::bit_width(x) << '\n';
    }
}

Godbolt

上试试

答案 1 :(得分:1)

<块引用>

是否有一种简单的方法可以让函数在编译时评估时使用一个代码块,以便它可以是 constexpr 安全的,并且在运行时使用不同的代码块,以便它可以快速? (如果是这样,这也与我的其他一些问题有关。)

从 C++20 开始,是的! std::is_constant_evaluated 正是为了这个目的。

所以你现在可以:

SELECT MAX(water) FROM kn1 WHERE datetime > TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 month)) ORDER BY datetime