Переадресация типа возврата в универсальном коде
Для неуниверсального кода, как и в приведенном вами примере, вы можете вручную выбрать ссылку в качестве типа возврата:
auto const& Example(int const& i)
{
return i;
}
но в общем коде вы хотите иметь возможность полностью пересылать возвращаемый тип, не зная, имеете ли вы дело со ссылкой или значением. decltype(auto)дает вам эту способность:
template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
Задержка вывода типа возврата в рекурсивных шаблонах
В этих вопросах и ответах несколько дней назад возникла бесконечная рекурсия во время создания шаблона, когда тип возврата шаблона был указан decltype(iter(Int<i-1>{}))вместо decltype(auto).
template<int i>
struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto)
{ return iter(Int<i-1>{}); }
int main() { decltype(iter(Int<10>{})) a; }
decltype(auto)используется здесь для отсрочки вычета типа возврата после того, как пыль от создания экземпляра шаблона исчерпана.
Другое использование
Вы также можете использовать decltype(auto)в других контекстах, например, в проекте стандарта N3936 также говорится
7.1.6.4 автоматический спецификатор [dcl.spec.auto]
1 Спецификаторы типа autoи decltype(auto)типа обозначают тип заполнителя, который будет заменен позже, либо путем вычитания из инициализатора, либо путем явного указания типа конечного возврата. Спецификатор autoтипа также используется, чтобы показать, что лямбда - это общая лямбда.
2 Тип заполнителя может появляться с объявителем функции в decl-specier-seq, type-specier-seq, translation-function-id или trailing-return-type в любом контексте, где такой декларатор допустим . Если декларатор функции включает в себя тип конечного возврата (8.3.5), это указывает на объявленный тип возврата функции. Если объявленный тип возврата функции содержит тип заполнителя, тип возврата функции выводится из операторов возврата в теле функции, если таковые имеются.
Черновик также содержит этот пример инициализации переменной:
int i;
int&& f();
auto x3a = i; // decltype(x3a) is int
decltype(auto) x3d = i; // decltype(x3d) is int
auto x4a = (i); // decltype(x4a) is int
decltype(auto) x4d = (i); // decltype(x4d) is int&
auto x5a = f(); // decltype(x5a) is int
decltype(auto) x5d = f(); // decltype(x5d) is int&&
auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i; // decltype(x7a) is int*
decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)