Подтвердить что ты не робот

Почему мы не можем автоматически выводить возвращаемые типы?

Недавно я работал с другом, который хотел сделать С++ более Haskell-y, и нам нужна функция, которая в основном выглядит так:

auto sum(auto a, auto b) {
    return a + b;
}

По-видимому, я не могу использовать auto как тип параметра, поэтому я изменил его на это:

template<class A, class B>
auto sum(A a, B b) {
    return a + b;
}

Но это тоже не работает. Что мы в конце концов поняли, нам нужно это:

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b) {
    return a + b;
}

Итак, мой вопрос в том, какой смысл? Разве не decltype просто повторять информацию, так как компилятор может просто посмотреть на оператор return?

Я подумал, что, возможно, это необходимо, поэтому мы можем просто включить заголовочный файл:

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b);

... но мы все равно не можем использовать такие шаблоны.

Другая вещь, которую я рассматривал, заключалась в том, что компилятор может быть проще, но похоже, что на самом деле это будет сложнее.

Случай 1: с decltype

  • Выясните тип оператора decltype
  • Выясните типы возвращаемых значений
  • Посмотрите, соответствуют ли они

Случай 2: Без decltype

  • Выясните типы возвращаемых значений
  • Посмотрите, соответствуют ли они

Итак, с учетом этих вещей, какая точка возвращаемого возвращаемого типа с decltype?

4b9b3361

Ответ 1

Что делать, если у нас есть следующее:

template<class A, class B, class C>
auto sum(A a, B b, C c) {
   if (rand () == 0) return a + b;

   // do something else...

    return a + c;
}

.. где выражения a + b и a + c дают разные типы результатов. Что должен компилятор решить поставить как возвращаемый тип для этой функции и почему? Этот случай уже рассматривается С++ 11 lambdas, которые позволяют опустить возвращаемый тип, если операторы return могут быть выведены одному типу (требуется стандартная цитата из NB), некоторые источники утверждают, что разрешено только одно возвращаемое выражение, и что это является gcc-глюком).


Техническая причина состоит в том, что С++ позволяет определять и декларировать отдельные.

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b);

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b)
{
}

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

С++ должен учитывать все возможности. Ограничение возвращаемых типов возвращаемых значений только определением функций означает, что вы не можете сделать что-то простое:

template<class A, class B>
class Foo
{
  auto sum(A a, B b) -> decltype(a + b);
}

template<class A, class B>
auto Foo<A, B>::sum(A a, B b) -> decltype(a + b)
{
}

Ответ 2

но мы все равно не можем использовать такие шаблоны.

Во-первых, возвращаемые возвращаемые типы не являются просто шаблоном. Они работают для всех функций. Во-вторых, говорит кто? Это совершенно законный код:

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b);

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b)
{
}

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

С++ должен учитывать все возможности. Ограничение возвращаемых типов возвращаемых значений только определением функций означает, что вы не можете сделать что-то простое:

template<class A, class B>
class Foo
{
  auto sum(A a, B b) -> decltype(a + b);
}

template<class A, class B>
auto Foo<A, B>::sum(A a, B b) -> decltype(a + b)
{
}

И это довольно часто для многих программистов. Нет ничего плохого в том, что вы хотите кодировать этот путь.

Единственная причина, по которой lambdas уйти без возвращаемого типа, состоит в том, что они должны иметь тело функции, определенное с определением. Если вы ограничили типы возвращаемых возвратов только теми функциями, в которых было определено определение, вы не сможете использовать любой из перечисленных случаев.

Ответ 3

Нет никаких технических причин, почему это невозможно. Основная причина, по которой они не связаны, заключается в том, что язык С++ движется очень медленно, и для добавления функций требуется очень много времени.

Вы можете получить хороший синтаксис с lambdas (но вы не можете иметь templacized аргументы в lambdas, опять же без уважительной причины).

auto foo = [](int a, double b)
{
    return a + b;
};

Да, есть случаи, когда тип возврата не может быть автоматически выведен. Точно так же, как в лямбда, это может быть просто требованием объявить тип возврата в этих двусмысленных случаях.

В настоящий момент ограничения настолько произвольны, что их сложно расстраивать. Также см. Удаление понятий для добавления разочарования.

Ответ 5

Маленькая надежда уговорить комитет добавить такую ​​языковую функцию, хотя никаких технических препятствий нет. Но, возможно, можно убедить группу GCC добавить расширение компилятора.