4
votes

Quel est le type de constructeur?

Je sais que le constructeur n'a pas de type de retour. Bien que je me demande, quel est alors le type de constructeur? Un constructeur a-t-il un type?

J'ai essayé ceci

prog.cc: In function 'int main()':
prog.cc:5:32: error: decltype cannot resolve address of overloaded function
    5 | int main() { foo< decltype(A::A) > f; }
      |                                ^
[...]

pour obtenir l'erreur (gcc)

int main() { foo< decltype(A::A) > f; }

... eh bien, je ne peux pas prendre l'adresse. Cela échoue également:

prog.cc: In function 'int main()':
prog.cc:5:32: error: taking address of constructor 'constexpr A::A(A&&)'
    5 | int main() { foo< decltype(&A::A) > f; }
      |                                ^
prog.cc:5:35: error: template argument 1 is invalid
    5 | int main() { foo< decltype(&A::A) > f; }
      |                                   ^

avec

struct A { A() {} };

template <typename A> struct foo;

int main() { foo< decltype(&A::A) > f; }

qui est probablement juste un message d'erreur très déroutant causé par la même raison que ci-dessus (ne peut pas prendre l'adresse du constructeur) et je ne sais pas quoi essayer d'autre ..

Quel est le type d'un constructeur?

S'il a aucun type, alors qu'est-ce que c'est? Ce n'est certainement pas A (member_function) () .

PS : Pour clarifier ma confusion: cpprefernce états

Constructor est une fonction membre non statique spéciale d'une classe qui est utilisé pour initialiser les objets de son type de classe.

Et ma logique est la suivante: les fonctions membres ont un type, les constructeurs sont des types spéciaux de fonctions membres, donc ils devraient avoir un type. Je sais que le raisonnement est erroné, mais pourquoi?


18 commentaires

S'il n'a pas de type de retour, il n'a pas de type.


@ user207421 pas très convaincant. Un int n'a pas de type de retour et son type est int


@ formerlyknownas_463035818 Parce que ce n'est pas une fonction ...


@ formerlyknownas_463035818 Pas très convaincant. La question concerne les constructeurs, pas les types intégrés.


@FedericoklezCulloca Je suppose que oui, mais par exemple cppref déclare "Le constructeur est une fonction membre non statique spéciale d'une classe qui" et généralement les fonctions membres ont un type


"Un int n'a pas de type de retour et son type est int " quelle légende


Et généralement, «spécial» indique une exception à la règle générale, et c'est l'une d'entre elles. Un autre est que vous ne pouvez pas l'appeler directement, et un autre est que vous ne pouvez pas prendre son adresse, et encore un autre est qu'il n'a pas de nom à des fins de recherche de nom.


@SuperSimplePimpleDimple non ce n'est pas void . Et le "bouffon" faisait référence à un simple int dans un commentaire sournois de ma part.


@SuperSimplePimpleDimple s'il vous plaît restez classe. Appeler quelqu'un un "bufoon" n'aide personne et obtiendra probablement votre commentaire autrement utile signalé.


@LightnessRacesinOrbit ok je n'ai pas tout lu, j'ai commenté trop vite parce que c'était une déclaration amusante que "les ints n'ont pas de types de retour et ils ont encore des types" et le gars qui a dit "parce qu'ils ne sont pas des fonctions" - je pensait qu'il disait que les constructeurs ne sont pas des fonctions.


@SuperSimplePimpleDimple juste parce que quelque chose est implémenté "bas niveau" de la même manière qu'une fonction est, ne dit rien sur son type. Les types C ++ sont un concept purement théorique et ne doivent pas être confondus avec la manière dont les implémentations C ++ les traitent.


@PeterT Je suis d'accord avec la deuxième partie de cette déclaration, mais je pense avoir trouvé la solution à ce "problème". J'essaierai de faire quelque chose, si je n'obtiens pas d'erreur, j'enverrai le code dans une réponse.


@SuperSimplePimpleDimple rappelez-vous simplement que dans les langages avec un comportement indéfini (comme C ++) "Si je n'obtiens pas d'erreur" n'est pas une barre assez haute pour considérer quelque chose de correct.


@SuperSimplePimpleDimple PeterT a raison et c'est peut-être votre malentendu. La question ne visait pas à comprendre comment le compilateur implémente les constructeurs. En fait, même si je savais quel type de constructeur est, je ne peux pas faire grand-chose avec cette information, en ce sens c'est une question plutôt académique.


@SuperSimplePimpleDimple C'était moi, et je ne l'étais pas.


Le point d'un type de fonction est un pointeur vers elle. Le point d'un pointeur est d'avoir plusieurs éléments sur lesquels il peut pointer.


@curiousguy a un sens, bien qu'il ne semble pas que ce soit la règle que le comité suit lors de l'introduction d'un type. nullptr_t est ce qui me vient à l'esprit comme parfait contre-exemple


@ formerlyknownas_463035818 C ++ avait beaucoup de ces UDT (type défini par l'utilisateur, pas l'utilisateur est dans l'utilisateur final, mais pas les types intégrés): le STL d'origine est rempli de types de balises (un type d'information zéro utilisé pour distinguer les surcharges); seul un vrai support pour lambda et les concepts peut rendre ces tas de balises redondantes. Pour en revenir aux ctors, puisqu'ils n'ont pas de noms, la seule façon d'en avoir deux qui prenaient le même paramètre d'exécution était une balise (pensez "complex (x, y)" vs "complex (theta, arg)") comme " complexe (thêta, arg, polaire ()) ". Dans la bibliothèque de support du langage, il y a aussi l'opérateur new non lanceur.


3 Réponses :


9
votes

Je pense que ces citations du standard C ++ 17 seront pertinentes (Constructeurs 15.1)

1 Les constructeurs n'ont pas de noms ....

et

2 Un constructeur est utilisé pour initialiser les objets de son type de classe. Étant donné que les constructeurs n'ont pas de noms, ils ne sont jamais trouvés lors de la recherche de noms ; cependant une conversion de type explicite utilisant le la notation fonctionnelle (8.5.1.3) provoquera l'appel d'un constructeur à initialiser un objet. [Remarque: pour l'initialisation des objets de classe tapez voir 15.6. - note de fin]

et

10 Une instruction return dans le corps d'un constructeur ne doit pas spécifier valeur de retour. L'adresse d'un constructeur ne doit pas être prise.


1 commentaires

Pourriez-vous également ajouter: Une instruction return dans le corps d'un constructeur ne doit pas spécifier de valeur de retour. L'adresse d'un constructeur ne doit pas être prise. -> 11.3.4 6



5
votes

Les constructeurs n'ont effectivement pas de types.

Il peut être surprenant que la norme ne le dise pas explicitement, mais comme ils n'ont pas de noms, ne participent pas à la recherche de noms, ne peuvent pas avoir leur adresse prise et sont des «fonctions» sans type de retour, c'est déductible.


6 commentaires

Les constructeurs n'ont effectivement pas de types. Je m'attendrais à ce que la majorité des compilateurs l'interprètent comme un type de retour void . C'est la même chose sur le plan fonctionnel.


@NO_NAME bon point. Il peut être utile de vérifier comment les fonctions void sont traduites en assembly et si les constructeurs sont similaires dans ce cas.


@NO_NAME Il est possible que, dans le code généré, un constructeur ressemble un peu à une fonction membre de retour de void , oui. Mais cela ne nous dit rien sur le type réel dans le C ++ réel


@NO_NAME Non. Je ne m'attendrais pas seulement mais exigerais que tous les compilateurs l'interprètent comme exprimé dans la norme. Si vous trouvez une exception, veuillez l'indiquer ici.


@ user207421 Si vous avez une citation de la norme qui dit que les constructeurs doivent retourner void, veuillez écrire une réponse à la question.


@NO_NAME Ils ne le font pas, et ce n'est pas le cas, et c'est exactement le but.



0
votes

S'ils avaient un type, que pourriez-vous faire? Rien du tout. C'est pourquoi:

S'ils en avaient un, vous pourrez peut-être obtenir le pointeur vers un constructeur en prenant son adresse (prendre l'adresse d'une entité surchargée est sans ambiguïté si le résultat est immédiatement utilisé syntaxiquement pour initialiser un pointeur du bon type).

S'ils avaient des pointeurs vers eux, que pourriez-vous faire? Exactement rien.

Ils n'ont pas de nom. Un pointeur non nul vers le constructeur de A pointera toujours vers & A :: A . Vous pouvez aussi bien supprimer le passe-partout du pointeur et "appeler le constructeur" directement.


0 commentaires