使用constexpr + auto作为返回值和参数类型的怪异类型推导

问题描述 投票:0回答:1

我一直在使用编译器优化和编译器资源管理器,并且注意到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’

这怎么会引发错误,而第一个示例不会?

c++ g++ compiler-optimization c++20
1个回答
1
投票

当您定义这样的函数时:

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的参数的类型。

© www.soinside.com 2019 - 2024. All rights reserved.