示例代码:
#include <cstdint>
//#define USE_CONSTEXPR_INTRINSICS
#if defined (USE_CONSTEXPR_INTRINSICS)
namespace intrin
{
[[nodiscard]] constexpr int lsb(std::uint64_t value)
{
int r = 0;
while (value <<= 1) ++r;
return 63 - r;
}
}
#else
namespace intrin
{
[[nodiscard]] inline int lsb(std::uint64_t value)
{
return __builtin_ctzll(value);
}
}
#endif
constexpr int f(std::uint64_t v)
{
return intrin::lsb(v);
}
#if defined (USE_CONSTEXPR_INTRINSICS)
static_assert(f(13) == 3);
#endif
int main() {}
有一个“内在”函数lsb
,我可以有条件地将其编译为 constexpr - 以允许使用 static_assert 进行静态测试(这也是有条件编译的,与 constexpr 内在函数相同)。
问题来自于 f
被标记为 constexpr - 这使得当 lsb
不是 constexpr 时它的格式不正确。
目前我通过
#if defined (USE_CONSTEXPR_INTRINSICS)
#define INTRIN_CONSTEXPR constexpr
#else
#define INTRIN_CONSTEXPR inline
#endif
然后将 f
声明为
INTRIN_CONSTEXPR int f(std::uint64_t v)
但对我来说这个解决方案并不理想,因为有许多函数使用 lsb
,有时非常间接,并且它变得难以跟踪(不需要诊断,所以有时它因编译器而异)并且不合适。我更喜欢的是仅在需要时进行检查 - 例如在 static_assert 周围 - 并且编译器在其他情况下保持沉默。
目前有什么方法可以使其更加自动化吗? future 是否有希望变得更容易?
最佳答案
C++20 通过 std::is_constant_evaluated
使这变得微不足道
[[nodiscard]] constexpr int lsb(std::uint64_t value)
{
if (std::is_constant_evaluated())
{
int r = 0;
while (value <<= 1) ++r;
return 63 - r;
}
else
{
return __builtin_ctzll(value);
}
}
在 constexpr 上下文中:
static_assert(lsb(1) == 0); // OK
在运行时上下文中:
auto test(int n)
{
return lsb(n);
}
编译为:
test(int):
movsx rax, edi
rep bsf rax, rax
ret
请注意,它不是 if constexpr(std::is_constant_evaluated())
。这将始终返回 true
。
对于任何查看此内容的人,为了简洁起见,alg 是不完整的,lsb(0)
应该返回 64
。
关于c++ - 具有条件 constexpr 被调用者的 constexpr 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57672044/