在C++ 11中,sqrt被定义为constexpr?

sep*_*p2k 39 c++ constexpr c++11

在C++ 11中std::sqrt定义为constexpr,即它可以合法地从其他constexpr函数或编译时上下文中使用,如数组大小或模板参数吗?g ++似乎允许它(使用-std=c++0x),但我不确定我是否可以将其视为权威,因为c ++ 0x/c ++ 11支持仍然不完整.我似乎无法在互联网上找到任何东西的事实让我不确定.

看起来这应该是人们可以轻易找到使用谷歌的东西,但我已经尝试过(现在40分钟......)并且找不到任何东西.我可以找到几个建议,将constexpr添加到标准库的各个部分(例如这个),但没有关于sqrt或其他数学函数.

Nic*_*las 25

std::sqrtconstexpr根据N3291第26.8节,没有定义为:C++ 11 FDIS(我怀疑他们之后将其添加到最终标准中).有人可能会编写这样的版本,但标准库版本却没有constexpr.

  • 这是明确说明的吗?26.8 C库没有提及constexpr.如果除了那些没有强制执行的函数之外,它还提供了constexpr函数实现,那么它肯定仍然符合要求. (2认同)

Ara*_*raK 23

为了防止任何人对元整数平方根函数感兴趣,这里是我之前写的一个:

constexpr std::size_t isqrt_impl
    (std::size_t sq, std::size_t dlt, std::size_t value){
    return sq <= value ?
        isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1;
}

constexpr std::size_t isqrt(std::size_t value){
    return isqrt_impl(1, 3, value);
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*tof 16

这是一个快速有效的constexpr实现double浮点数.float如果需要,您也可以调整它:

#include <limits>   

namespace Detail
{
    double constexpr sqrtNewtonRaphson(double x, double curr, double prev)
    {
        return curr == prev
            ? curr
            : sqrtNewtonRaphson(x, 0.5 * (curr + x / curr), curr);
    }
}

/*
* Constexpr version of the square root
* Return value:
*   - For a finite and non-negative value of "x", returns an approximation for the square root of "x"
*   - Otherwise, returns NaN
*/
double constexpr sqrt(double x)
{
    return x >= 0 && x < std::numeric_limits<double>::infinity()
        ? Detail::sqrtNewtonRaphson(x, x, 0)
        : std::numeric_limits<double>::quiet_NaN();
}
Run Code Online (Sandbox Code Playgroud)


Lin*_*umz 13

下面是一个使用二进制搜索的constexpr平方根实现.对于gcc和clang,它可以正常工作到2 ^ 64,其他更简单的版本通常会因数字> 2 ^ 32而失败,因为编译器将递归深度限制为例如200.

// C++11 compile time square root using binary search

#define MID ((lo + hi + 1) / 2)

constexpr uint64_t sqrt_helper(uint64_t x, uint64_t lo, uint64_t hi)
{
  return lo == hi ? lo : ((x / MID < MID)
      ? sqrt_helper(x, lo, MID - 1) : sqrt_helper(x, MID, hi));
}

constexpr uint64_t ct_sqrt(uint64_t x)
{
  return sqrt_helper(x, 0, x / 2 + 1);
}
Run Code Online (Sandbox Code Playgroud)

下面是一个更好的版本(对于整数常量)需要C++ 14,它类似于Baptiste Wicht 博客文章中提供的版本.允许C++ 14 constexpr函数使用局部变量和if语句.

// C++14 compile time square root using binary search

template <typename T>
constexpr T sqrt_helper(T x, T lo, T hi)
{
  if (lo == hi)
    return lo;

  const T mid = (lo + hi + 1) / 2;

  if (x / mid < mid)
    return sqrt_helper<T>(x, lo, mid - 1);
  else
    return sqrt_helper(x, mid, hi);
}

template <typename T>
constexpr T ct_sqrt(T x)
{
  return sqrt_helper<T>(x, 0, x / 2 + 1);
}
Run Code Online (Sandbox Code Playgroud)

  • 甚至可以仅使用一个级别的递归并使`mid`成为一个函数:http://coliru.stacked-crooked.com/a/f6e2be98d2c2aed6 (3认同)

Ale*_*nov 9

现在有一个提案P1383R0 More constexpr for <cmath>and <complex>(Edward J. Rosten, Oliver J. Rosten)不幸的是没有进入 C++20 并且从最新的评论来看也可能不在 C++23 中。C++26?


Sha*_*our 8

如果我们查看最接近C++ 11 N3337的标准草案,我们可以看到sqrt没有标记为constexpr,来自26.8 c.math部分:

这些标头的内容分别与标准C库标头相同,但有以下更改:

没有任何的变化包括增加constexprsqrt.

我们可以从问题中看出,gcc将非常量表达式函数的内置函数视为常量表达式,将gcc许多数学函数标记为constexpr作为扩展.这个扩展是一个不合格的扩展,正如我在gcc实现时对链接问题的回答中所注意到的,它看起来像是一个符合标准的扩展,但是这个改变了,gcc并且可能会修复这个扩展以使其符合要求.