web-dev-qa-db-fra.com

Quelles sont certaines utilisations de decltype (auto)?

Dans c ++ 14, la decltype(auto) idiome est introduite.

Son utilisation consiste généralement à autoriser les déclarations auto à utiliser les règles decltype de l'expression donnée .

En recherchant des exemples de "bon" usage de l'idiome, je ne peux penser qu'aux choses suivantes (by Scott Meyers ), à savoir pour la déduction du type de retour d'une fonction :

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

Existe-t-il d'autres exemples dans lesquels cette nouvelle fonctionnalité de langage est utile?

128
Nikos Athanasiou

Renvoyer le type de transmission en code générique

Pour le code non générique, comme l'exemple initial que vous avez donné, vous pouvez sélectionner manuellement pour obtenir une référence en tant que type de retour:

auto const& Example(int const& i) 
{ 
    return i; 
}

mais en code générique vous voulez pouvoir transmettre parfaitement un type de retour sans savoir s’il s’agit d’une référence ou d’une valeur. decltype(auto) vous donne cette capacité:

template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}

Retarder la déduction du type de retour dans les modèles récursifs

Dans ce Q & A il y a quelques jours, une récursion infinie lors de l'instanciation du modèle a été rencontrée lorsque le type de retour du modèle a été spécifié comme decltype(iter(Int<i-1>{})) au lieu de 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) est utilisé ici pour retarder la déduction du type de retour une fois que la poussière d'instanciation du modèle est tombée.

Autres utilisations

Vous pouvez également utiliser decltype(auto) dans d'autres contextes, par exemple. le projet de norme N3936 indique également

7.1.6.4 spéci fi cateur automatique [dcl.spec.auto]

1 Les spéci fi cateurs de types auto et decltype(auto) désignent un type de marque de réservation qui sera remplacé ultérieurement, soit par déduction d'un initialiseur, soit par spéci fi cation explicite avec un type de retour-fin. Le spécificateur de type auto est également utilisé pour indiquer qu'un lambda est un lambda générique.

2 Le type d’espace réservé peut apparaître avec un déclarateur de fonction dans les instructions decl-specifier-seq, type-specifier-seq, conversion-function-id ou fin. -return-type, dans tout contexte dans lequel un tel déclarateur est valide . Si le déclarateur de fonction inclut un type de retour-fin (8.3.5), spécifie le type de retour déclaré de la fonction. Si le type de retour déclaré de la fonction contient un type d'espace réservé, le type de retour de la fonction est déduit des instructions de retour figurant dans le corps de la fonction, le cas échéant.

Le brouillon contient également cet exemple d'initialisation de variable:

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)
142
TemplateRex

Citer des trucs de ici :

  • decltype(auto) est principalement utile pour déduire le type de retour des fonctions de transfert et des wrappers similaires , où vous souhaitez que le type soit exactement "suivi" une expression que vous invoquez.

  • Par exemple, étant donné les fonctions ci-dessous:


   string  lookup1();
   string& lookup2();

  • En C++ 11, nous pourrions écrire les fonctions d'encapsuleur suivantes, dont le but est de préserver la référence du type de retour:

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

  • En C++ 14, nous pouvons automatiser cela:

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

  • Cependant, decltype(auto) n'est pas destiné à être une fonctionnalité largement utilisée au-delà de cela.

  • En particulier, bien que cela puisse être utilisé pour déclarer des variables locales , cela n’est probablement qu’un simple anti-modèle car la référence d’une variable locale ne devrait pas dépendre du expression d'initialisation.

  • En outre, il est sensible à la façon dont vous écrivez l'instruction return.

  • Par exemple, les deux fonctions ci-dessous ont des types de retour différents:


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

  • Le premier renvoie string, le second renvoie string&, Qui est une référence à la variable locale str.

De la proposition vous pouvez voir plus d'utilisations prévues.

26
101010