我一直在使用编译器优化和编译器资源管理器,并且注意到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 )
,但是即使我传递了一个长双精度字面值,这种情况仍然存在。
这导致溢出。
为什么编译器在编译时不能推断出我的返回类型应该是double?我本来希望,因为fib被标记为constexpr,并且我正在使用-O3进行编译,所以即使我传递了整数,g ++也可以通过认识到fib是指数函数来推断出需要两倍。
即使以上内容很难实现,但为什么不能通过长双精度字面量来解决问题呢?我希望函数能意识到该函数的第三个分支必须返回一个长双精度数,因此返回类型应该是一个长双精度数。
当fib更改为返回0.l和1.l时,编译器仅意识到需要长双精度,如下所示:
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’
这怎么会引发错误,而第一个示例不会?
当您定义这样的函数时:
constexpr auto f(auto x)
{
return 42;
}
编译器具有no choice,但可以将返回类型推论为int
,因为这是文字42
的类型。是否使用其他类型的参数调用f
都没关系:
f(42.l);
返回类型仍然是int
,尽管x
的类型是long double
。
但是,您可以明确要求返回类型与参数类型相同:
constexpr auto f(auto x) -> decltype(x)
{
return 42;
}
现在返回值将转换为调用f
的参数的类型。