【发布时间】:2020-09-13 10:10:11
【问题描述】:
我一直在使用编译器优化和编译器资源管理器,并注意到 g++ 9.3 中的以下缺点(本地测试)。这个问题似乎在 g++ 10.1 中仍然存在(在编译器资源管理器上测试)。我正在使用
注意以下代码:
#include <iostream>
#include <iomanip>
constexpr auto fib( auto x )
{
if( x == 0 )
return 0;
else if( x == 1 )
return 1;
else
return fib( x - 1 ) + fib( x - 2 );
}
int main( int argc, char * argv[] )
{
std::cerr << std::setprecision(10) << fib( 47.l );
}
编译器资源管理器链接here。
我知道如果我输入 47,模板参数推导会推导出函数 int foo( int x ),但即使我传递了一个长的双精度字面值,这种情况仍然存在。
这会导致溢出。
为什么编译器不能在编译时推断出我的返回类型应该是双精度?我本来希望,因为 fib 被标记为 constexpr,并且我正在使用 -O3 进行编译,所以即使我传递了一个整数,g++ 也能够通过意识到 fib 是指数来推断出需要双精度数。
即使上面的内容非常困难,为什么传入一个长的双精度字面量也不能解决问题?我希望函数意识到函数的第三个分支必须返回一个 long double,所以返回类型应该是一个 long double。
编译器仅在 fib 更改为返回 0.l 和 1.l 时才意识到需要 long double,如下所示:
constexpr auto fib( auto x )
{
if( x == 0 )
return 0.l;
else if( x == 1 )
return 1.l;
else
return fib( x - 1 ) + fib( x - 2 );
}
有趣的是,只将其中一个返回值更改为长双精度字面值,如下所示:
if( x == 0 )
return 0.l;
else if( x == 1 )
return 1;
导致以下错误:
error: inconsistent deduction for auto return type: ‘long double’ and then ‘int’
这怎么会抛出错误,但第一个例子不会?
【问题讨论】:
-
推断返回类型仅取决于函数中的返回语句,而不取决于传入的参数类型。
-
仅仅因为你的函数参数是双精度数并不意味着函数会返回双精度数。函数返回的唯一值不是0就是1,所以一定是int,这和返回int和int相加的结果就是int是一致的。因此,无论其参数是什么,该函数都会返回一个 int。
-
"g++ 将能够通过意识到 fib 是指数来推断出需要双精度数" - 这不是
auto(或模板类型推断)的工作方式。您指定类型(有时是间接的),编译器会应用它们。不允许根据它认为你可能会如何使用一个函数来任意选择。 -
我会喜欢心灵感应编译器。做我想做的而不是我告诉他们做的程序将使我的生活更轻松。但我必须从我的播放列表中删除终结者配乐。这可能会很糟糕。
-
编译器资源管理器告诉我函数签名是 int fib int。我现在明白为什么返回类型是int,但是为什么参数类型也是int?
标签: c++ g++ compiler-optimization c++20