我有以下代码的问题,我试图写一个编译时平方根函数。代码在最近的clang 6.0上编译。但是在gcc 8.0的最新版本上失败了。问题似乎是结构的初始化。
GCC输出
error: uninitialized variable 'sqrtNewtonRaphson' in 'constexpr' context
} sqrtNewtonRaphson;
^~~~~~~~~~~~~~~~~
此代码编译的最后一个gcc版本是GCC6.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;
}
GCC是正确的;叮当声是错误的。
根据[basic.types],您的匿名结构是聚合类型(因此是文本类型),因此它应该是constexpr可构造的。(N4659§6.9/10)
但是,您没有初始化聚合。聚合不是在声明时默认构造的。这就是为什么在之后添加大括号{}
可以使它工作(聚合初始化)
constexpr
函数要求根据[dcl.constexpr]§10.1初始化所有变量。5/3.4.5(强调矿山)
constexpr函数的定义应满足以下要求:
[…]
-其函数体应为=delete
,=default
,或不包含
如果您添加一个constexpr
构造函数,那么它也会工作(类型仍然是文本,但不再是聚合的,因此不需要显式初始化它)。但是,这也需要您命名结构。
只需将其作为另一个功能移出即可:
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使方法静态
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();
}