web-dev-qa-db-fra.com

L'héritabilité des lambdas est-elle garantie par la norme?

Dans la norme C++, les types de fermeture sont définis comme suit:

[expr.prim.lambda.closure] Le type d'une expression lambda (qui est également le type de l'objet fermeture ) Est un type de classe unique, sans nom et non nommé, appelé fermeture type , dont les propriétés sont décrites ci-dessous. [...]

La norme ne semble pas définir si le type de classe non-union non nommé est définitif ou non. Un compilateur implémentant les lambdas en tant que classes finales serait-il conforme à la norme ou avons-nous la garantie que nous pouvons hériter de lambdas?

La question n'est pas de savoir s'il est utile ou non d'hériter de lambdas: c'est une donnée que cela est utile. La question est de savoir si la norme fournit cette garantie.

16
Vincent

Oui, le type de fermeture ne doit pas être définitif. Au moins c'est mon interprétation.

§8.1.5.1 Types de fermeture [expr.prim.lambda.closure]

Une implémentation peut définir le type de fermeture différemment de ce qui est décrit ci-dessous à condition que cela ne modifie pas le comportement observable du programme autrement qu'en changeant:

  • ... [Ne s'applique pas]

La norme ne décrit alors pas le type de fermeture comme étant définitif. Le rendre final modifierait le comportement observable lorsque le type de fermeture ne doit pas être définitif.

En ce qui concerne le comportement observable. Considère ceci:

auto l = []{};
return std::is_final_v<decltype(l)>;

Rendre le type de fermeture définitif modifierait clairement le comportement observable d'un programme valide.


En ce qui concerne un cas d'utilisation, il peut s'agir d'une fonctionnalité très utile:

template <class... Fs> struct Overload : Fs ...
{
    using Fs::operator()...;
};

template <class... Fs> Overload(Fs...) -> Overload<Fs...>;

auto test()
{
    Overload f = {[] (int a) { return a * 100; },
                  [] (int a, int b) { return a + b;}};

    return f(1) + f(2, 3); // 105
}

Voyez-le en action sur godbolt


Merci à hvd et à rakete1111 pour les discussions et commentaires dans les commentaires.

18
bolov

L'effet de final est spécifié dans [class]/3 :

Si une classe est marquée avec le class-virt-specifierfinal et qu'elle apparaît sous la forme d'un class-or-decltype dans une base-clause, le programme est mal formé.

Autrement dit, peu importe que le cours soit final. Peu importe que la classe soit marquée avec le spécificateur final. Puisqu’un type de fermeture n’a pas de déclaration dans le fichier source, il est impossible de le marquer avec final et donc [class]/3 ne s’applique pas.

0
cpplearner