32 votes

Pourquoi les lambdas génériques sont-ils autorisés alors que les structures imbriquées avec des méthodes basées sur des modèles ne le sont pas?

Comme je le comprends - générique lambdas sont transformés en objets de portée locale avec les structures de type "modèle" operator(). Cela rend générique lambda très puissant et facile à utiliser l'outil. D'autre part, l'on peut créer des structures imbriquées dans la fonction, en revanche, si la structure a modélisé membre par exemple:

#include <iostream>

int main() {
    struct inner {
    template <class T>
       void operator()(T &&i) { }
    };
    return 0;
}

ou est modélisé par lui-même:

int main() {
    template <class T>
    struct inner {
       void operator()(T &&i) { }
    };
    return 0;
}

compilateur semble avoir un problème avec le compiler:

error: invalid declaration of member template in local class

et

error: a template declaration cannot appear at block scope

Je suppose que le problème réside plus dans la norme c++ que dans le compilateur bug. Quelles sont les raisons lambdas sont autorisés à avoir modélisé les membres et non pas les structures locales?

J'ai trouvé cette qustion, mais je pense que la réponse est du genre obsolète (je ne pense pas que c'est vrai même pour le c++11).

27voto

Columbo Points 11661

C'est la question centrale 728, qui a été déposée avant le générique lambdas agissait d'une chose.

Vous avez mentionné générique lambdas et qu'ils étaient identiques pour les classes locales avec des membres correspondants template operator(). Cependant, ils ne le sont pas vraiment, et les différences sont liées à la mise en œuvre de ses caractéristiques. Envisager

template <typename T>
class X {
    template <typename>
    void foo() {
        T t;
    }
};

Et

template <typename T>
auto bar() {
    return [] (auto) {T t;};
};

L'instanciation de ces modèles avec des <void> sera parfait dans le premier cas, mais mal-formé dans la deuxième. Pourquoi amende dans le premier cas? foo n'ont pas besoin d'être instantiatable pour chaque T, mais seulement l'un d'eux (ce serait [temp.res]/(8.1)).

Pourquoi mal formé dans le second cas? Le générique lambda corps est instancié - partiellement - à l'aide du gabarit fourni des arguments. Et la raison de cette instanciation partielle est le fait que...

...le lexique des étendues utilisées lors du traitement d'une définition de fonction sont fondamentalement transitoire, ce qui signifie que le report de l'instanciation d'une partie d'un modèle de fonction définition est difficile à soutenir.

(Richard Smith), Nous devons instancier assez de la local de "modèle" pour les rendre indépendants du contexte local (qui comprend les paramètres du modèle de la fonction englobante modèle).

C'est également liée à la justification de [expr.prim.lambda]/13, qui exige qu'une entité est implicitement capturé par un lambda si il...

les noms de l'entité dans une potentiellement-de l'expression évaluée ([base.def.odr]) où la enfermant pleine expression dépend d'un générique de paramètre lambda déclarée dans le large spectre de la lambda-expression.

C'est, si j'ai un lambda comme [=] (auto x) {return (typename decltype(x)::type)a;}a est quelque bloc-portée variable à partir d'une fonction englobante, indépendamment de si xs'membre typedef est pour void ou pas, le casting sera la cause d'une capture d' a, parce que nous devons nous décider sur ce, sans attendre un appel de la lambda. Pour une discussion de ce problème, voir l' origine de la proposition de génériques lambdas.

La ligne de fond est que complètement le report de l'instanciation d'un membre de modèle n'est pas compatible avec le modèle utilisé par (au moins un) majeur de la mise en œuvre(s), et étant donné que ceux sont les attendus de la sémantique, la fonctionnalité n'a pas été introduit.


Est que la motivation première de cette contrainte? Il a été introduit quelque part entre janvier et Mai 1994, avec pas de papier couvrant, donc nous ne pouvons avoir une idée approximative de l'état de l'notions de ce documents'justification de pourquoi les classes ne sont pas des arguments template:

Modèles de classe et les classes générées à partir du modèle sont de portée mondiale les entités et ne peut pas se référer à une portée locale entités.

Peut-être à l'époque, on voulait l'EMBRASSER.

3voto

Barry Points 45207

Je suppose que le problème réside plus dans la norme c++

Correct. Cela est stipulé dans [temp] pour les modèles de classe:

Un modèle de déclaration peuvent n'apparaître que comme un espace de noms de la portée ou l'étendue de classe de la déclaration.

et [temp.mem] pour les modèles de membre:

Une classe locale de la non-fermeture de type ne doit pas avoir des modèles de membre.


Quelles sont les raisons lambdas sont autorisés à avoir modélisé les membres et non pas les structures locales?

Parce qu'une fois que nous avons eu lambdas en C++11, il a été jugé qu'il serait extrêmement utile d'étendre ce concept à l'avoir génériques lambdas. Il y avait une proposition pour une telle extension du langage, qui a été révisé et a révisé et adopté.

D'autre part, il n'y a pas encore eu une proposition présentée (pour autant que je suis conscient d'une brève recherche) qui définit la motivation pour le besoin de modèles de membre dans les locaux des classes qui n'est pas adéquatement résolus par un générique lambda.

Si vous pensez que c'est un problème important qui doit être résolu, n'hésitez pas à soumettre une proposition après la pose sérieux et de la motivation pour pourquoi les modèles de membre sont importantes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X