Fonction C declarators
Tout d'abord, il y a C. En C, A a()
est de déclaration de fonction. Par exemple, putchar
a la déclaration suivante. Normalement, de telles déclarations sont stockées dans des fichiers d'en-tête, mais rien ne vous empêche de les écrire manuellement, si vous savez comment la déclaration de la fonction ressemble. Les noms d'arguments sont facultatifs dans les déclarations, j'ai donc omis dans cet exemple.
int putchar(int);
Cela permet d'écrire le code comme ceci.
int puts(const char *);
int main() {
puts("Hello, world!");
}
C vous permet également de définir des fonctions qui prennent des fonctions comme arguments, avec de belles lisible syntaxe qui ressemble à un appel de fonction (eh bien, c'est lisible, tant que vous n'aurez pas de retourner un pointeur de fonction).
#include <stdio.h>
int eighty_four() {
return 84;
}
int output_result(int callback()) {
printf("Returned: %d\n", callback());
return 0;
}
int main() {
return output_result(eighty_four);
}
Comme je l'ai mentionné, C, permet d'omettre les noms d'argument dans les fichiers d'en-tête, donc l' output_result
ressemblerait à ceci dans le fichier d'en-tête.
int output_result(int());
Un argument au constructeur
Ne reconnaissez-vous pas? Eh bien, permettez-moi de vous rappeler.
A a(B());
Yep, c'est exactement la même déclaration de fonction. A
est int
, a
est output_result
, et B
est int
.
Vous pouvez facilement remarquer un conflit de C avec de nouvelles fonctionnalités de C++. Pour être exact, les constructeurs étant nom de la classe et de la parenthèse, et suppléant de la syntaxe de déclaration avec ()
au lieu de =
. De par sa conception, C++ essaie d'être compatible avec le code en C, et donc il doit composer avec cette affaire - même si pratiquement personne ne s'en soucie. Donc, vieux C caractéristiques ont la priorité sur les nouvelles fonctionnalités C++. La grammaire de déclarations essaie de faire correspondre le nom de la fonction, avant de revenir à la nouvelle syntaxe, ()
si elle échoue.
Si l'une de ces fonctions n'existent pas, ou a une syntaxe différente (comme {}
en C++11), ce problème ne serait jamais arrivé pour la syntaxe avec un argument.
Maintenant, vous demandez peut-être pourquoi A a((B()))
travaux. Eh bien, nous allons déclarer output_result
inutile parenthèses.
int output_result((int()));
Il ne fonctionnera pas. La grammaire exige la variable de ne pas être entre parenthèses.
<stdin>:1:19: error: expected declaration specifiers or ‘...' before ‘(' token
Cependant, C++ s'attend à ce standard d'expression ici. En C++, vous pouvez écrire le code suivant.
int value = int();
Et le code suivant.
int value = ((((int()))));
C++ attend expression à l'intérieur à l'intérieur des parenthèses pour être... eh bien... d'expression, contrairement à la type C attend. Les parenthèses ne veux pas dire quoi que ce soit ici. Toutefois, en insérant inutile parenthèses, la fonction C de la déclaration n'est pas adapté, et la nouvelle syntaxe peut être appariés correctement (ce qui attend simplement une expression, telle qu' 2 + 2
).
En plus des arguments dans le constructeur
Sûrement un argument, c'est sympa, mais ce que sur les deux? Ce n'est pas que les constructeurs peuvent avoir un seul argument. L'une des classes intégrées qui prend deux arguments est - std::string
std::string hundred_dots(100, '.');
C'est super bien (techniquement, il aurait plus délicate à analyser si il serait écrit comme std::string wat(int(), char())
, mais soyons honnêtes - qui serait d'écrire? Mais supposons que ce code a un problème épineux. Vous pourriez penser que vous devez mettre tout entre parenthèses.
std::string hundred_dots((100, '.'));
Pas tout à fait ainsi.
<stdin>:2:36: error: invalid conversion from ‘char' to ‘const char*' [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' [-fpermissive]
basic_string<_CharT, _Traits, _Alloc>::
^
Je ne sais pas pourquoi g++ essaie de convertir char
de const char *
. De toute façon, le constructeur a été appelé avec juste une valeur de type char
. Il n'y a pas de surcharge qui a un argument de type char
, donc le compilateur est confus. Vous pouvez demander - pourquoi l'argument est de type char?
(100, '.')
Oui, ,
ici est un opérateur virgule. L'opérateur virgule prend deux arguments, et donne le côté droit de l'argument. Il n'est pas vraiment utile, mais c'est quelque chose d'être connu pour mes explications.
Au lieu de cela, pour résoudre la plus délicate à analyser, le code suivant est nécessaire.
std::string hundred_dots((100), ('.'));
Les arguments sont dans les parenthèses, pas la totalité de l'expression. En fait, l'une des expressions de besoins pour être entre parenthèses, comme c'est suffisant pour casser le C de la grammaire légèrement à utiliser le C++ fonctionnalité. Les choses qui nous amène au point de zéro arguments.
Les arguments zéro dans le constructeur
Vous avez peut-être remarqué l' eighty_four
fonction dans mon explication.
int eighty_four();
Oui, c'est aussi affectée par la plus délicate à analyser. C'est une définition valable, et on vous probablement avez vu si vous avez créé des fichiers d'en-tête (et vous devriez). L'ajout de parenthèses ne résout pas le problème.
int eighty_four(());
Pourquoi donc? Eh bien, ()
n'est pas une expression. En C++, vous devez mettre une expression entre parenthèses. Vous ne pouvez pas écrire auto value = ()
en C++, car ()
ne veut rien dire (et même si vous n'avez, comme vide de n-uplet (voir Python), il serait un argument, pas zéro). Pratiquement, cela signifie que vous ne pouvez pas utiliser d'abréviation syntaxe sans l'aide de C++11 {}
de la syntaxe, comme il n'y a pas d'expressions pour mettre dans les parenthèses, et C de la grammaire pour les déclarations de fonction s'appliquent toujours.