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


недавно я работал с другом, который хотел сделать C++ более 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 просто повторяя информацию, так как компилятор может просто посмотреть на возврат заявление?

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

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

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

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

Случай 1: С decltype

  • выяснить тип decltype сообщении
  • выяснить типы любого возврата значения
  • посмотреть, если они совпадают

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

  • выясните типы любых возвращаемых значений
  • посмотреть, если они совпадают

Итак, имея в виду эти вещи, в чем смысл трейлинг-типа возврата с decltype?

5 51

5 ответов:

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

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 выражения дают разные результаты. Что компилятор должен решить поставить в качестве возвращаемого типа для этой функции и почему? В этом случае уже включен в C++11 лямбда-выражения, которые позволяют не указывать тип возвращаемого значения, как долго, как return операторы могут быть выведены к тому же типу (необходима стандартная цитата NB, некоторые источники утверждают, что разрешено только одно возвращаемое выражение и что это gcc затруднение.)


техническая причина заключается в том, что C++ позволяет разделять определение и объявление.

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)
{
}

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

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

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)
{
}

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

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

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)
{
}

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

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

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)
{
}

и это довольно распространено для многих программистов. Нет ничего плохого в желании кодировать таким образом.

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

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

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

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

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

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

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

[]min(x, y)
{ return x < y ? x : y }

это основано на возможном предложении для полиморфных лямбд. Он тоже начал работать здесь при обновлении clang для поддержки этого синтаксиса.

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