web-dev-qa-db-fra.com

Fonction C++ retournant la fonction

Où dans la norme les fonctions renvoyant des fonctions sont-elles interdites? Je comprends qu’ils sont ridicules sur le plan conceptuel, mais il me semble que la grammaire le leur permettrait. Selon cette page Web, un " noptr-declarator [est] tout déclarateur valide " qui inclurait le déclarateur d'une fonction:

int f()();

Concernant la syntaxe.

Il me semble que la syntaxe, telle qu’elle est décrite dans [dcl.decl], permet

int f(char)(double)

qui pourrait être interprété comme la fonction} _ fcela prend uncharet renvoie une fonction avec la même signature queint g(double).

1    declarator:
2       ptr-declarator
3       noptr-declarator parameters-and-qualifiers trailing-return-type
4    ptr-declarator:
5        noptr-declarator
6        ptr-operator ptr-declarator
7    noptr-declarator:
8        declarator-id attribute-specifier-seq opt
9        noptr-declarator parameters-and-qualifiers
10       noptr-declarator [ constant-expression opt ] attribute-specifier-seq opt
11       ( ptr-declarator )
12    parameters-and-qualifiers:
13       ( parameter-declaration-clause ) cv-qualifier-seqAfter

Grosso modo, après 1-> 2, 2 = 4, 4-> 6, 4-> 6 Vous devriez avoir Opérateur ptr Opérateur ptr Opérateur ptr Ensuite, utilisez 4-> 5, 5 = 7, 7-> 8 pour le premier déclarant; utilisez 4-> 5, 5 = 7, 7-> 9 pour les deuxième et troisième déclarants. 

27
Hector

De [dcl.fct], assez explicitement:

Les fonctions ne doivent pas avoir de type de retour de type tableau ni fonction , bien qu'elles puissent avoir un type de retour de tapez un pointeur ou une référence à de telles choses. Il ne doit pas y avoir de tableaux de fonctions, bien qu'il puisse y en avoir des pointeurs vers les fonctions.

Avec C++ 11, vous voulez probablement juste:

std::function<int()> f();
std::function<int(double)> f(char);

Il y a une certaine confusion concernant la grammaire C++. L'instruction int f(char)(double);can peut être analysée en fonction de la grammaire. Voici un arbre d'analyse:

grammar

De plus, une telle analyse est même significative sur la base de [dcl.fct]/1:

Dans une déclaration T DD a la forme
D1 (parameter-declaration-clause) cv-qualifier-seqopt
ref-qualifieropt exception-specificationopt attribut-specifier-seqopt
et le type de déclarator-id contenu dans la déclaration T D1 est “Derive-Declarator-Type-ListT”, le type de déclarator-id dans D est “derive-declarator-type-list fonction de (parameter-declaration-clause) cv-qualifier-seqoptref-qualifieropt return T ”.

Dans cet exemple, T == int, D == f(char)(double), D1 == f(char). Le type de déclarator-id dans T D1 (int f(char)) est "fonction de (caractère) renvoyant int". Donc, dérivé-déclarateur-type-liste est "fonction de (char) retournant". Ainsi, le type de f serait lu comme "fonction de (char) retournant la fonction de (double) retournant int."

C'est finalement beaucoup de bruit pour rien, car il s'agit d'un formulaire de déclaration explicitement interdit. Mais pas par la grammaire. 

54
Barry

À moins que vous ne renvoyiez un pointeur ou une référence à une fonction qui soit ok, l’alternative consiste à renvoyer une copie d’une fonction. Maintenant, réfléchissez à quoi une copie d’une fonction ressemble, se comporte, se comporte. Ce serait d’abord un tableau d’octets, ce qui n’est pas autorisé non plus, et le second de tous ces octets serait l’équivalence d’un morceau de code renvoyant littéralement un morceau de code ... presque tous les scanneurs de virus heuristiques considérez qu’il s’agit d’un virus car il n’y aurait aucun moyen de vérifier la viabilité du code renvoyé par le système d’exécution ou même au moment de la compilation. Même si vous pouviez renvoyer un tableau, comment renverriez-vous une fonction? Le principal problème avec le retour d'un tableau (qui serait une copie sur la pile) est que sa taille est inconnue et qu'il est donc impossible de le supprimer de la pile. Le même dilemme existe pour les fonctions (où le tableau serait le code binaire en langage machine). De plus, si vous rendiez une fonction de cette manière, comment la retourneriez-vous et l'appeleriez-vous?

En résumé, la notion de renvoi d'une fonction plutôt que d'un point à une fonction échoue car il s'agit d'un tableau de taille inconnue de code machine placé (copié) sur la pile. Ce n'est pas quelque chose que C ou C++ a été conçu pour permettre, et avec le code, il est maintenant possible de faire demi-tour et d'appeler cette fonction, surtout si vous vouliez passer des arguments.

J'espère que cela a du sens

0
ydobonebi

La grammaire formelle de C interdit en réalité de renvoyer des fonctions, mais on peut toujours renvoyer un pointeur de fonction qui, à toutes fins utiles, semble être ce que vous voulez faire:

  int (*getFunc())(int, int) { … }

Je suis obsédé par le fait de dire que la grammaire est une explication plus fondamentale du manque de prise en charge d'une telle fonctionnalité. Les règles de la norme sont une dernière préoccupation.

Si la grammaire ne fournit pas un moyen d'accomplir quelque chose, je ne pense pas que la signification de la sémantique ou de la norme soit importante pour un langage sans contexte donné.

0
Anzurio