2017-07-27 70 views
3

我遇到以下代码有问题,我正在编写一个编译时平方根函数。代码编译最近的铛铛6.0。 在最新版本的gcc 8.0上失败。这个问题似乎与结构的初始化有关。在constexpr函数中嵌套的struct,在clang中编译,在gcc中失败

GCC输出

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

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

//------------------------------------------------------------ 
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编译的,以及铿锵。为什么是这样?

//------------------------------------------------------------ 
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

现场演示https://godbolt.org/g/xw8rcr – DanielCollier

+1

顺便说一句,为什么你需要一个嵌套的结构在这里? – erenon

+0

@erenon因为我不需要在其他地方调用函数。并且递归lambda不是一件事 – DanielCollier

回答

3

GCC是正确的;铿锵是错的。

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

但是,您并未初始化您的聚合。声明时,聚合不是默认构建的。这就是为什么加括号{}事后使其能够工作(集合初始化)

一个constexpr功能要求所有变量每[dcl.constexpr]§10.1.5/ 3.4.5(重点煤矿

初始化

一个constexpr函数应满足下列要求的定义:
[...]
—其功能体= delete= default,或不包含
的化合物语句          —非文字类型或静态或线程存储时限的或者其中没有 进行初始化的变量的定义。

如果添加了constexpr构造函数,那么它也将工作(类型仍然字面但不再聚集,所以你不需要明确的初始化)。但是,这也需要你命名你的结构。

+0

谢谢!我不会想到这一点。你会建议向叮当报告吗? – DanielCollier

+0

@DanielCollier:我会的。我承认从来没有向他们提交过错误报告(尽管时间久了),所以我对这个过程并不熟悉。 – AndyG

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; 
} 

编辑制作方法静态

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(); 
} 
+1

我知道我可以做到这一点,但我想知道什么是海湾合作委员会不接受它但铿锵的问题。我也不想创建另一个函数,因为除了compile_time_sqrt函数之外,它不会被使用。使用羊羔会很好,但我不认为这是可能的 – DanielCollier

+0

Lamba *我不是动物 – DanielCollier

+1

如果你想保留在结构中,你实际上不需要一个实例。见编辑 – IlBeldus