В этом примере они означают одно и то же.
Однако есть несколько преимуществ последовательного использования формы конечного типа возврата (Фил Нэш называет эти «Функции восточного конца» , поскольку тип возврата находится на восточном конце).
Использование параметров. Очевидно, что при использовании параметров для определения типа возврата вы должны использовать конечный тип возврата.
template <typename T>
auto print(T const& t) -> decltype(std::cout << t) { return std::cout << t; }
Поиск имени. В конечном типе возврата поиск имени включает в себя область действия класса для определений функций-членов. Это означает, что вам не нужно повторно вводить класс, если вы хотите вернуть вложенный класс:
Type C::foo() { ... } // error: don't know what Type is
C::Type C::foo() { ... } // ok
auto C::foo() -> Type { ... } // ok
Аналогично, для определения функций-членов, где имя класса по какой-то причине должно быть неоднозначным, чтобы оно находилось в глобальном пространстве имен, а тип возвращаемого значения - класс:
D ::C::foo() { ... } // error, parsed as D::C::foo() { ... }
auto ::C::foo() -> D { ... } // ok
В некоторых случаях обязателен тип трейлинг-возврата, есть случаи, когда он полезен, и есть случаи, когда он делает то же самое. Не бывает случаев, когда это хуже по причинам, отличным от простого подсчета символов.
Плюс, математически мы привыкли думать о функциях как A -> B
, а не как о B(A)
, и поэтому auto(*)(A) -> B
как указатель на функцию, принимающую A
и возвращающую B
, немного ближе к этому мнению, чем B(*)(A)
.
<час />
С другой стороны, написание auto main() -> int
выглядит нелепо.
<ч />
В конечном счете, это чисто мнение. Просто напишите код, который работает.