Présentation des langages

C3 se positionne comme un successeur minimaliste de C/C++, sans ramasse‑miettes ni exceptions, et expose explicitement le code exécuté à la compilation grâce au préfixe $. Zig, quant à lui, propose une réflexion limitée à la phase de compilation via @typeInfo et des fonctions comptime. C++ possède déjà un support de réflexion basé sur std::meta et prépare une extension officielle dans les futures normes.

Mécanismes de réflexion

En C++, la fonction générique enum_to_string parcourt std::meta::enumerators_of et compare chaque valeur à l’argument. Le code utilise ^^E pour obtenir le type et [:r:] pour accéder à l’enum. Cette approche est entièrement résolue à la compilation, aucune surcharge runtime n’est introduite.

template<typename E> constexpr std::string_view enum_to_string(E value){
  for(const auto r: std::meta::enumerators_of(^^E)){
    if(value==[:r:]) return std::meta::identifier_of(r);
  }
  return "Unknown";
}

Zig ne propose pas de métaprogrammation générique comparable. L’exemple montre une méthode to_string attachée à chaque enum, avec un switch explicite. La réflexion se limite à l’interrogation du type via @typeInfo dans la fonction printStructFields, où chaque champ est parcouru en boucle inline for. Aucun mécanisme de génération automatique d’enum‑to‑string n’existe.

fn printStructFields(value:anytype) void{
  comptime{assert(@typeInfo(@TypeOf(value))==."struct");}
  inline for(@typeInfo(@TypeOf(value))."struct".fields) |field|{
    std.debug.print("{s}: {any},\n", .{field.name, @field(value, field.name)});
  }
}

C3 utilise des macros préfixées par $ qui s’exécutent à la compilation. Le macro String enum_to_string($enum_val) récupère le type via $Typeof, itère sur les valeurs avec $foreach et renvoie la description associée. Cette syntaxe rend la réflexion visible dans le code source et évite toute ambiguïté entre compile‑time et runtime.

macro String enum_to_string($enum_val){
  var $EnumType = $Typeof($enum_val);
  $foreach $val : $EnumType :: values {
    $if $val == $enum_val:
      return $val.description;
    $endif
  }
}

Analyse comparative

Le modèle de C++ repose sur une API standardisée (std::meta) qui offre un accès complet aux membres, aux identifiants et aux valeurs d’enum. La généricité est assurée par les templates, ce qui permet d’écrire une fonction unique pour tous les enums. Zig, en revanche, nécessite une implémentation manuelle par enum, ce qui augmente la maintenance mais reste simple à comprendre. C3 combine la concision des macros avec une syntaxe explicite, mais dépend d’un préprocesseur propriétaire qui n’est pas encore standardisé.

En termes de performances, les trois solutions sont résolues à la compilation : aucune surcharge d’exécution n’est introduite. Cependant, la complexité du code généré diffère. C++ génère du code inline optimisé par le compilateur, Zig produit du code de boucle résolu à la compilation, et C3 insère du texte pré‑traité qui peut être moins optimisé si le compilateur ne reconnaît pas les patterns.

Limites et perspectives

Le principal frein de Zig est l’absence d’une API de réflexion générique comparable à std::meta. Les développeurs doivent dupliquer le même switch pour chaque enum, ce qui peut entraîner des incohérences. C3, bien que prometteur, repose sur une syntaxe de macro qui n’est pas encore supportée par les outils d’analyse statique classiques, limitant l’intégration CI/CD. C++ bénéficie d’un écosystème mature, mais son support de réflexion reste expérimental et dépendra de l’adoption des futures normes.

En conclusion, C++ offre la solution la plus complète et standardisée, Zig reste limité à des cas spécifiques, et C3 propose une approche originale qui gagnera en pertinence si son modèle de macro se stabilise et s’intègre aux chaînes d’outils existantes.