Почему мы не можем автоматически определить типы возвращаемых данных? - PullRequest
51 голосов
/ 29 сентября 2011

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

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

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

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

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

Случай 1: С decltype

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

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

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

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

Ответы [ 5 ]

38 голосов
/ 29 сентября 2011

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

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)
{
}
8 голосов
/ 29 сентября 2011

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

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

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

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

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

5 голосов
/ 29 сентября 2011

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

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

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

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

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

0 голосов
/ 21 июня 2012

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

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

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

0 голосов
/ 05 октября 2011

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

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