constexpr函数内的嵌套结构,在clang中编译,在gcc中失败

时间:2017-07-27 11:15:42

标签: c++ gcc language-lawyer constexpr clang++

我遇到以下代码的问题,我正在尝试编写一个编译时平方根函数。该代码汇编了最新的clang 6.0。 但最新版本的gcc 8.0失败了。这个问题似乎与结构的初始化有关。

GCC输出

 error: uninitialized variable 'sqrtNewtonRaphson' in 'constexpr' context
     } sqrtNewtonRaphson;
       ^~~~~~~~~~~~~~~~~

此代码编译的gcc的最后一个版本是gcc 6.3,之后的以下版本中,compile_time_sqrt_ver1(double)无法编译。

//------------------------------------------------------------
constexpr double
compile_time_sqrt_ver1(double x) {
    struct {
        constexpr double operator() (double x, double current, double previous) {
            return current == previous ? current : (*this)(x, 0.5 * (current + x / current), current);
        }
    } sqrtNewtonRaphson; 

    return x >= 0 && x < std::numeric_limits<double>::infinity()
           ? sqrtNewtonRaphson(x, x, 0)
           : std::numeric_limits<double>::quiet_NaN();
}

//------------------------------------------------------------
int main() {
    constexpr double test_v1 = compile_time_sqrt_ver1(24);
    return test_v1;
}

我发现的解决方案是在结构的末尾添加{},使其在最新版本的gcc和clang中进行编译。这是为什么?

//------------------------------------------------------------
constexpr double
compile_time_sqrt_ver2(double x) {
    struct {
        constexpr double operator() (double x, double current, double previous) {
            return current == previous ? current : (*this)(x, 0.5 * (current + x / current), current);
        }
    } sqrtNewtonRaphson{}; // <- change {}

    return x >= 0 && x < std::numeric_limits<double>::infinity()
           ? sqrtNewtonRaphson(x, x, 0)
           : std::numeric_limits<double>::quiet_NaN();
}

//------------------------------------------------------------
int main() {
    constexpr double test_v2 = compile_time_sqrt_ver2(24);
    return test_v2;
}

2 个答案:

答案 0 :(得分:3)

海湾合作委员会是对的; Clang错了。

Per [basic.types]你的匿名结构是一个聚合类型(因此是一个文字类型),所以它应该是constexpr可构造的。 (N4659§6.9/ 10)

但是,您没有初始化聚合。聚合不是在声明时默认构造的。这就是为什么之后添加大括号{}使其能够工作(聚合初始化)

的原因

constexpr函数要求根据[dcl.constexpr]§10.1.5/ 3.4.5初始化所有变量(强调我的

  

constexpr函数的定义应满足以下要求:
[...]
- 其 function-body 应为= delete,{{ 1}},或不包含的复合语句 - 非文字类型或静态或线程存储持续时间的变量的定义,或者对于   初始化已执行

如果添加= default构造函数,那么它也可以工作(类型保持文字但不再是聚合的,因此您不需要显式初始化它)。但是,这也需要您为结构命名。

答案 1 :(得分:1)

将其移出另一个功能:

constexpr double sqrtNewtonRaphson (double x, double current, double previous) {
            return current == previous ? current : sqrtNewtonRaphson(x, 0.5 * (current + x / current), current);
        }
constexpr double compile_time_sqrt_ver2(double x) {
    return x >= 0 && x < std::numeric_limits<double>::infinity()
           ? sqrtNewtonRaphson(x, x, 0)
           : std::numeric_limits<double>::quiet_NaN();
}

//------------------------------------------------------------
int main() {
    constexpr double test_v2 = compile_time_sqrt_ver2(24);
    return test_v2;
}

EDIT make method static

constexpr double compile_time_sqrt_ver2(double x) {
    struct SNR{
        static constexpr double sqrtNewtonRaphson (double x, double current, double previous) {
            return current == previous ? current : sqrtNewtonRaphson(x, 0.5 * (current + x / current), current);
        }
    }; 

    return x >= 0 && x < std::numeric_limits<double>::infinity()
           ? SNR::sqrtNewtonRaphson(x, x, 0)
           : std::numeric_limits<double>::quiet_NaN();
}