France IOI: Qui a été sélectionné pour le stage du 6 au 12 juillet ?

Il existe une incompatibilité syntaxique entre le C et le C++

La voici, extraite d'un cours de Christian Casteyde (oui, je sais, il enseigne du C/C++ et son cours n'est plus du tout à jour, mais il y a tout de même des éléments intéressants) :

" Note : La norme C99 fournit également une autre syntaxe plus pratique pour initialiser les structures. Cette syntaxe permet d'initialiser les différents champs de la structure en les nommant explicitement et en leur affectant directement leur valeur. Ainsi, avec cette nouvelle syntaxe, l'initialisation précédente peut être réalisée de la manière suivante :

Exemple 3-8. Initialisation de structure C99

/* Déclare et initialise la variable John : */
struct Client John={
.Taille = 190,
.Age = 35,
.Comptes[0] = 13594,
.Comptes[1] = 45796
};

On constatera que les champs qui ne sont pas explicitement initialisés sont, encore une fois, initialisés à leur valeur nulle. De plus, comme le montre cet exemple, il n'est pas nécessaire de respecter l'ordre d'apparition des différents champs dans la déclaration de la structure pour leur initialisation.

Il est possible de mélanger les deux syntaxes. Dans ce cas, les valeurs pour lesquelles aucun nom de champ n'est donné seront affectées au champs suivants le dernier champ nommé. De plus, si plusieurs valeurs différentes sont affectées au même champ, seule la dernière valeur indiquée sera utilisée.

Cette syntaxe est également disponible pour l'initialisation des tableaux. Dans ce cas, on utilisera les crochets directement, sans donner le nom du tableau (exactement comme l'initialisation des membres de la structure utilise directement le point, sans donner le nom de la structure en cours d'initialisation). On notera toutefois que cette syntaxe n'est pas disponible en C++. Avec ce langage, il est préférable d'utiliser la notion de classe et de définir un constructeur. Les notions de classe et de constructeur seront présentées plus en détails dans le Chapitre 8. C'est l'un des rares points syntaxiques où il y a incompatibilité entre le C et le C++. "

JaJa quoi mon esprit pur en est traumatisé.
.
.
.
Nan j'ai menti mon esprit n'est pas pur du tout, WHAHAHA. Car ça sert à rien un esprit pur de toute manière.

Bien qu'ils s'écrivent de la même manière un code en C peut compiler sur un compilateur C++.
Mais on doit penser differement (moins) en C++ car on est avec des objets.
C'est ca ?

J'ai commencé en ADA et je code maintenant en C ou C++.

"je peux autant bien coder en C++ pure qu'en C pure"

Là, tu es un menteur.
Et doublement.
Parce que le C++ pur (pas de e), c'est quoi ? Et déjà, quelle version de la norme ? (Oui, la question qui tue, la plupart du temps.)

Et puis, t'as de la chance qu'epsilon soit pas encore passé par là, je crois. :-°

Bon, je vais mettre les choses au point, simplement: Je sais coder en C++11 et C++03, et je sais aussi coder en C99.
Le C++ pur, façon de dire, que je n'utilise pas de cast à la C, pas de structs (sauf si vraiment nécessaire), etc...
Le C pur, c'est ne pas utiliser le C++ du tout.

Enfin (Je suis désolé, du malentendu), si on revenait au sujet ?

Quand je dis, je code C/C++, c'est que je peux autant bien coder en C++ "pur" (C++11, C++03) qu'en C "pur" (C99) (Façon de dire)
Non, je code pas avec un mélange de deux, moi-même, je trouve ça dégueulasse.

EDIT: Message plus explicite et corrigé (Vraiment désolé, encore je ne demande qu'à apprendre, si je dit des conneries, corrigez-moi)

"Je sais coder en C++11 et C++03"

Si je savais déjà "coder" en C++03, j'en serais heureux.
Après, si coder, c'est faire deux/trois projets, alors oui, je sais.

Mais je pense que "savoir", c'est plutôt être capable de savoir ce que fera *n'importe quel code* sans avoir besoin d'aller fouiller sur le net.
Et ça, c'est dur.
Surtout si je commence à te sortir quelque chose d'UB au milieu de choses parfaitement définies.
(Exemples pour tester à la fin du message)

"Le C++ pur, façon de dire, que je n'utilise pas de cast à la C, pas de structs (sauf si vraiment nécessaire), etc..."
"pas de cast à la C" -> Ça, c'est bien.
"pas de structs" -> Ça, c'est à voir. Parce que les structs peuvent être utiles, pour séparer un peu les données des utilisateurs. (On a une discussion intéressante là-dessus sur dvpz en ce moment, cf. le thread sur les accesseurs.)
Et, donc, le C++ pur c'est juste ne pas utiliser le C ?

"Le C pur, c'est ne pas utiliser le C++ du tout."
Donc le C *pur*, c'est tout ce qui compile avec gcc -std=c11 ?

Je crois que tu oublies que tu emploies le terme "pur", ainsi que les termes "je sais" dans tes phrases... Non ?

Quelques exemples de test (inventés à l'arrache, mais ça serait intéressant de se faire un thread pour ça rien que pour se tester les uns les autres), à essayer de comprendre sans se servir d'internet : (Non, si je fais une faute de syntaxe idiote sans faire gaffe, ce n'est pas volontaire, c'est codé dans la boîte message prologin tout ça.)

auto foo() -> decltype([] () { return 42; }) { return [] () { return 42; }; }
===
int i = 1; int * volatile p = &i; while (*p) {}
===
int i = 1; volatile int * p = &i; while (*p) {}
===
int * volatile p = 0x42424242; while (*p) {}
===
int volatile * p = 0x42424242; while (*p) {}
===

1
2
3
template <template <typename> class C>
struct S { typedef typename C<int>::type type; };
typedef S<S>::type type; // Valide ?

===

1
2
3
4
5
template <template <typename> class C>
struct S { typedef typename C<int>::type type; };
template <typename T>
struct I { typedef T type; };
typedef S<I>::type t;

Bref, quelques exemples en vitesse...
Bon courage !

Je crois qu'on n'a plus rien à dire sur le sujet ; mais il serait par contre plus judicieux d'ouvrir une autre discussion si on veut continuer à parler de ça.

@Ekleog : Parfois, il est dur de pas devenir pointilleux quand on voit toutes les bêtises dîtes sur C++, hein ?
Si vous trouvez les codes d'Ekleog trop simple, je peux vous trouver plus compliqué. :D

Tenez, pour détendre l'atmosphère, je cite Sutter et Stroustrup au dernier meeting du WG21 :
Halpern suggests that the next standard have a codename. Sutter suggests C++ Fudge Sandwich. Stroustrup suggests Titanic.
Je ne veux donc pas voir un seul C++1y. Ce sera C++ Fudge Sandwich !

@Sylvain CHIRON : Je pense que la discussion d'origine est close. De plus on est assez habitué aux dérives de sujet sur ce forum, donc ça va. :)

@Ekleog : je n'ai compris que le premier exemple personnellement.

On déclare une fonction "foo" ne prenant aucun paramètre dont le type de retour est celui d'une fonction lambda ne prenant aucun paramètre et renvoyant un entier qui vaut 42. Elle renvoie une fonction lambda ne prenant aucun paramètre et qui renvoie un entier valant 42. Le type de retour de la fonction est déterminé automatiquement par le compilateur grâce à "auto" qui s'aide pour cela de la fonction "decltype".

Corrige moi si je me trompe.

J'ai toujours cru que "volatile" indiquait que la variable pouvait être modifié par un autre programme, mais je pense que c'est plus subtil que ça.

Pourrais-tu me l'expliquer ? Pour le moment tout les morceaux de code m'ont l'air de se contenter de déclarer (et initialiser) une variable puis d'affecter son adresse à un pointeur, ou d'affecter directement une adresse à un pointeur, avec le qualificatif "volatile" alternativement appliqué au pointeur et à la nature de la variable pointée, sans que la boucle "while" ait le moindre effet...

Pour l'avant dernier exemple je "crois" avoir compris mais j'ai un gros doute. L’exemple est complètement tordu tant il est complexe. Il me semble que l'opération est invalide mais je ne saurais pas dire exactement pourquoi... peut-être parce que la classe template S déclare un alias sur un type déclaré dans la classe template C prenant un entier en paramètre template. Et on déclare un alias sur cette classe template S ayant en paramètre template... la classe S. La nature récursive de la déclaration m'empêche de déterminer ce qui va se passer, mais étant donné que je tournerais en rond à l'infini si on me demandait la nature de l'alias, je crois que le compilateur planterait.

PS : en plus, le paramètre template obligatoire de S n'est pas spécifié dans la déclaration de l'alias.

Il ne faudrait pas plutôt faire :

typedef S >::type type;

Si je me trompe quelque part dans mon raisonnement expliquez le moi, je souhaite progresser !

Pour le dernier exercice j'ai la m\^me remarque à faire que ci-dessus.

Le premier test, renvoie un lambda qui renvoie un int, donc type de retour : std::function\<int>
Le sixième test, Invalide, car si on fait S est une struct template qui attend en template un template. Et de toute façon, si on fait S\<S>, type sera égale à S\<int>::type et int n'est pas un template.
S\<S>::type donc
S\<int>::type:
1. int n'est pas un template.
2. Je suis pas sûr, mais int::type = int car, la SFINAE permet ça.

Le septième test, Valide, car I est une struct template, Ensuite I possède un typedef correspondant à T et enfin:
S\<I>::type donc
I\<int>::type donc
type = int

Pour les volatiles, je connais pas trop, je sais juste que c'est utile en multithreading.

Encore désolé, si tu pense que j'utilise trop le mot, je sais, excuse-moi, je n'ai pas un grand vocabulaire.

@Structs: Personnellement, j'utilise les structures exclusivement pour la sérialisation.

edit epsilon012 : "\<" -> "<"

Vous parlez de "struct" depuis le début, mais qu'entendez vous par là ? Aggregate ? POD ?

Et vous vous trompez, le premier n'est pas valide…

FDIS (n3290) §5.1.2 [expr.prim.lambda] ¶2

> The evaluation of a lambda-expression results in a prvalue temporary
> (12.2). This temporary is called the closure object. A lambda-expression
> shall not appear in an unevaluated operand (Clause 5).
[ Note: A closure
> object behaves like a function object (20.8). -- end note ]
(La mise en gras est de moi)
Et oui…

Les 2 et 3 sont valides et sont des boucles infinis.
Alors que « int i=1; int *p=&i; while(*p){} » peut se terminer.

Les 4 et 5 sont invalides, la seule valeur étant une pointer literal et une integral literal est 0.

La 6 est invalide, S est un template ayant un template template parameter et non un template template template parameter. :)

La 7 est valide.

Sinon, @lgorythme, OzVessalius, il y a plusieurs erreurs dans ce que vous dites, je prendrais soin de les relever plus tard. :p Si Ekleog ne le fait pas avant. (et utilisez < à la place de \< et > à la place de >).

>> Les 2 et 3 sont valides et sont des boucles infinis.

Pourquoi ? Puisque les pointeur sont volatiles (ou que l'objet pointé est volatile) leur valeur peut changer au cours du programme même si aucune opération est effectué dans la boucle "while", non ?

>> Alors que « int i=1; int *p=&i; while(*p){} » peut se terminer.

Pourquoi ? La valeur de i n'est pas modifiée : elle reste à 1 tout le temps. De même pour p.

>> Les 4 et 5 sont invalides, la seule valeur étant une pointer literal et une integral literal est 0.

Développes, je ne comprend pas trop bien :/
En quoi est-il interdit d'initialiser des pointeurs avec une valeur hexadécimale directement ?

>> La 7 est valide.

Pourquoi ? oO

Cela ressemble fort à l'exemple précédent.

D'où tenaient vous vos connaissances ? Vous avez fait une école d'ingénieurs ? Je désespère de ne pas en savoir autant... comment faites vous ??? J'ai bien envie de progresser en C++ mais je ne vois rien d'autre que des tutoriels pour débutants sur le net.

Pour chaque exemple, je suppose que c'est la seule ligne. S'il y a une autre partie du code qui modifie les variables forcément, c'est différent.

Et oui, il peut terminer à cause de :

FDIS (n3290) §1.10 [intro.multithread] ¶24

> The implementation may assume that any thread will eventually do one of
> the following:
>     -- terminate,
>     -- make a call to a library I/O function,
>     -- access or modify a volatile object, or
>     -- perform a synchronization operation or an atomic operation.
> [ Note: This is intended to allow compiler transformations such as removal
> of empty loops, even when termination cannot be proven. -- end note ]

Pour les 4 et 5, bah oui, par exemple void *p=42; n'est pas valide. En effet, pas de conversion int vers void*.

Pourquoi le 7 ne serait pas valide ?

Et si, il y a une "doc" officielle C++. C++ est un langage normalisé par l'ISO (contrairement à beaucoup d'autre langage). Ça s'appelle le standard ou « la norme », c'est des citations de celui ci que je donne quand je commence par FDIS… ou nXXXX…

ven, 22/06/2012 - 23:50 — OzVessalius

> Le 7 l'est grâce à la SFINAE.
SFINAE n'a rien à voir avec ça. SFINAE = Substitution Failure Is Not An Error, où est ce que tu vois une substitution failure là ?

ven, 22/06/2012 - 22:20 — @lgorythme

> la fonction "decltype".
Ce n'est pas une fonction. :) Mais un specifier (disons, keyword ou mot-clef).

ven, 22/06/2012 - 22:20 — @lgorythme

> J'ai toujours cru que "volatile" indiquait que la variable pouvait
> être modifié par un autre programme, mais je pense que c'est plus
> subtil que ça.
Et bien, c'est à peu près tout ce qu'il y a à retenir.

FDIS (n3290) §7.1.6.1 [dcl.type.cv] ¶7

> [ Note: volatile is a hint to the implementation to avoid aggressive
> optimization involving the object because the value of the object
> might be changed by means undetectable by an implementation. See 1.9
> for detailed semantics. In general, the semantics of volatile are
> intended to be the same in C++ as they are in C. -- end note ]
La sémentique exacte (plus ou moins définie en 1.9) n'est pas très intéressante. Il faut juste retenir que le volatile C++ n'a rien à voir avec le volatile Java, qui lui est plutôt équivalent à std::atomic.

ven, 22/06/2012 - 22:20 — @lgorythme

> Il ne faudrait pas plutôt faire :
> typedef S\<S\< /*un autre type*/ > >::type type;
S\<A>::type
Imaginons que :

  • A est une struct template prenant un template template parameter.
  • S est donc une struct template prenant un template template template parameter.

Mais si is_same\<A,S>…
S prend un template template parameter (point 1) et S prend un template template template parameter (point 2)… contradiction.

ven, 22/06/2012 - 22:20 — @lgorythme

> Pour le dernier exercice j'ai la m\^me remarque à faire que ci-dessus.
Fait la substitution… si tu remplaces C par I, tu obtiens I\<int>::type qui est égal à int. Pas de problème donc.

ven, 22/06/2012 - 22:42 — OzVessalius

> Le premier test, renvoie un lambda qui renvoie un int, donc type de
> retour : std::function\<int>
std::function\<int()> :)

ven, 22/06/2012 - 22:42 — OzVessalius

> 2. Je suis pas sûr, mais int::type = int car, la SFINAE permet ça.
Non int::type est une erreur syntaxique et le SFINAE n'a rien à voir avec ça (bis). :)

Répondre au sujet

Vous devez vous enregistrer ou vous connecter pour poster des messages.