Comment fonctionne le lambda générique (auto
mot-clé en tant que type d'argument) en standard C++ 14?
Est-il basé sur des modèles C++ où, pour chaque argument différent, le compilateur génère une nouvelle fonction avec le même corps mais des types remplacés (polymorphisme à la compilation) ou est-il plus similaire aux génériques de Java (effacement de types)?
Exemple de code:
auto glambda = [](auto a) { return a; };
Les lambdas génériques ont été introduits dans C++14
.
Simplement, le type de fermeture défini par l'expression lambda aura un opérateur d'appel basé sur un modèle plutôt que l'opérateur habituel, sans modèle, de [Lambdas de C++11
(bien sûr, lorsque auto
apparaît au moins une fois dans la liste des paramètres).
Donc, votre exemple:
auto glambda = [] (auto a) { return a; };
Fera glambda
une instance de ce type:
class /* unnamed */
{
public:
template<typename T>
T operator () (T a) const { return a; }
};
Le paragraphe 5.1.2/5 du projet de norme C++ 14 n3690 spécifie comment est défini l'opérateur d'opérateur du type de fermeture d'une expression lambda donnée:
Le type de fermeture d’une expression lambda non générique a un opérateur d’appel de fonction en ligne public (13.5.4) dont les paramètres et le type de retour sont décrits par la clause de déclaration de paramètre et le type de retour en fin de l'expression lambda. Pour un lambda générique, le type de fermeture a un modèle de membre d'opérateur d'appel de fonction en ligne public (14.5.2) dont la liste de paramètres-modèle est composée d'un paramètre de type modèle inventé pour chaque occurrence de auto dans le La clause de déclaration de paramètre de lambda, dans l'ordre d'apparition . Le type modèle-paramètre inventé est un paquet de paramètres si la déclaration de paramètre correspondante déclare un paquet de paramètres de fonction (8.3.5). Le type de retour et les paramètres de fonction du modèle d'opérateur d'appel de fonction sont dérivés du type de retour final et de la clause de déclaration de paramètre de l'expression lambda en remplaçant chaque occurrence de auto dans les spécificateurs de déclin de la clause de déclaration de paramètre par le nom de le modèle-paramètre inventé correspondant.
Finalement:
Est-ce similaire aux modèles où, pour chaque argument différent, le compilateur génère des fonctions avec le même corps mais les types modifiés, ou est-il plus similaire aux génériques de Java?
Comme l'explique le paragraphe ci-dessus, les lambdas génériques ne sont que des sucres syntaxiques pour des foncteurs uniques et non nommés avec un opérateur d'appel basé sur un modèle. Cela devrait répondre à votre question :)
Malheureusement , ils ne font pas partie de C++ 11 ( http://ideone.com/NsqYuq ):
auto glambda = [](auto a) { return a; };
int main() {}
Avec g ++ 4.7:
prog.cpp:1:24: error: parameter declared ‘auto’
...
Cependant , la manière dont cela pourrait être implémenté en C++ 14 selon le proposition de Portland pour les lambdas génériques :
[](const& x, & y){ return x + y; }
Ceci donnerait pour l'essentiel la création habituelle d'une classe de foncteur anonyme, mais en l'absence de types, le compilateur émettrait un membre basé sur un modèle -operator()
:
struct anonymous
{
template <typename T, typename U>
auto operator()(T const& x, U& y) const -> decltype(x+y)
{ return x + y; }
};
Ou selon la proposition la plus récente Proposition d'expressions lambda génériques (polymorphes)
auto L = [](const auto& x, auto& y){ return x + y; };
--->
struct /* anonymous */
{
template <typename T, typename U>
auto operator()(const T& x, U& y) const // N3386 Return type deduction
{ return x + y; }
} L;
Donc, oui, pour chaque permutation de paramètres, une nouvelle instanciation apparaîtrait, cependant, les membres de ce foncteur seraient toujours partagés (c'est-à-dire les arguments capturés).
C'est une fonctionnalité proposée par C++ 14 (et non pas en C++ 11) similaire (voire équivalente) aux modèles. Par exemple, N3559 fournit cet exemple:
Par exemple, cette instruction générique contenant une expression lambda:
auto L = [](const auto& x, auto& y){ return x + y; };
peut entraîner la création d'un type de fermeture et d'un objet similaire à la structure ci-dessous:
struct /* anonymous */ { template <typename T, typename U> auto operator()(const T& x, U& y) const // N3386 Return type deduction { return x + y; } } L;