Вывод странного типа с использованием constexpr + auto в качестве типа возврата и параметра - PullRequest
0 голосов
/ 26 мая 2020

Я играл с оптимизацией компилятора и проводником компилятора и заметил следующий недостаток в 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 );
}

Ссылка на обозреватель компилятора здесь .

Я понимаю, что если бы я поставил 47, вывод аргумента шаблона привел бы к функции int foo( int x ), но это сохраняется, даже когда я передаю длинный двойной литерал.

Это приводит к переполнению.

Почему компилятор не может сделать вывод во время компиляции, что мой возвращаемый тип должен быть двойным? Я ожидал, что, поскольку fib помечен как constexpr, а я компилирую с -O3, даже если бы я передал целое число, g ++ смог бы вывести, что требуется double, понимая, что fib был экспоненциальным.

Даже если это слишком сложно, почему передача длинного двойного литерала не решает проблему? Я ожидал, что функция поймет, что третья ветвь функции должна возвращать длинное двойное значение, поэтому тип возвращаемого значения должен быть длинным двойным.

Компилятор понимает, что длинное двойное значение требуется только тогда, когда fib изменяется на return 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’

Как это может выдать ошибку, но не первый пример?

1 Ответ

7 голосов
/ 26 мая 2020

Когда вы определяете функцию, подобную этой:

constexpr auto f(auto x) 
{
  return 42;
}

, компилятор не имеет выбора , кроме как вывести возвращаемый тип как int, потому что это тип литерала 42. Не имеет значения, вызываете ли вы f с аргументом какого-либо другого типа:

f(42.l);  

, возвращаемый тип по-прежнему int, хотя тип x равен long double.

Однако вы можете явно запросить, чтобы тип возвращаемого значения совпадал с типом аргумента:

constexpr auto f(auto x) -> decltype(x)
{
  return 42;
}

, и теперь возвращаемое значение будет преобразовано в тип аргумента, который f называется с.

...