我遇到以下代码的问题,我正在尝试编写一个编译时平方根函数。该代码汇编了最新的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;
}
答案 0 :(得分:3)
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();
}