Каковы некоторые виды использования decltype(auto)?

В C++14 decltype(auto) идиома вводится.

Обычно его использование позволяет auto декларации использовать decltype правила по данному выражению.

В поисках примеров "хорошего" использования идиомы я могу думать только о таких вещах, как ( Скотт Мейерс), а именно о выводе типа возвращаемого значения функции:

template<typename ContainerType, typename IndexType>                // C++14
decltype(auto) grab(ContainerType&& container, IndexType&& index)
{
  authenticateUser();
  return std::forward<ContainerType>(container)[std::forward<IndexType>(index)];
}

Есть ли другие примеры, где эта новая языковая функция полезна?

2 ответа

Решение

Переадресация типа возврата в универсальном коде

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

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)

Цитирую материал отсюда:

  • decltype(auto) прежде всего полезен для определения возвращаемого типа функций пересылки и аналогичных оболочек, где вы хотите, чтобы тип точно "отслеживал" некоторое выражение, которое вы вызываете.

  • Например, учитывая функции ниже:


   string  lookup1();
   string& lookup2();

  • В C++11 мы могли бы написать следующие функции-оболочки, которые не забывают сохранить ссылку на тип возвращаемого значения:

   string  look_up_a_string_1() { return lookup1(); }
   string& look_up_a_string_2() { return lookup2(); }

  • В C++14 мы можем автоматизировать это:

   decltype(auto) look_up_a_string_1() { return lookup1(); }
   decltype(auto) look_up_a_string_2() { return lookup2(); }

  • Тем не мение, decltype(auto) не предназначено, чтобы быть широко используемой особенностью кроме этого.

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

  • Кроме того, он чувствителен к тому, как вы пишете инструкцию возврата.

  • Например, две функции ниже имеют разные типы возврата:


   decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }
   decltype(auto) look_up_a_string_2() { auto str = lookup2(); return(str); }

  • Первое возвращение stringвторая возвращается string&, который является ссылкой на локальную переменную str,

Из предложения вы можете увидеть больше предполагаемого использования.

Другие вопросы по тегам