GCC 16.1, kas iznāca 30. aprīlī, ir pirmais plaši lietotais C++ kompilators, kas atbalsta refleksiju. Ar karodziņiem -std=c++26 -freflection programma tagad var kompilēšanas laikā izlasīt pati savu struktūru — uzskaitīt klases laukus, nolasīt enum vērtību nosaukumus un no tā ģenerēt jaunu kodu. Tā ir iespēja, ko C++ izstrādātāji gaidīja vairāk nekā desmit gadus.
Refleksija ienāca standartā kā priekšlikums P2996, ko komiteja iebalsoja C++26 sastāvā 2025. gada jūnija sanāksmē Sofijā. Pati C++26 valodas versija tika pabeigta 2026. gada 28. martā ISO sanāksmē Londonā. Līdz šim C++ struktūras lauku uzskaitīšanai vajadzēja X-makro trikus vai atsevišķu koda ģeneratoru; tagad to izdara pats kompilators.
Ko refleksija patiesībā dara
Refleksija pievieno valodai divas jaunas lietas. Pirmā ir operators ^^, kas no jebkura koda elementa — tipa, funkcijas, mainīgā — atgriež vērtību ar tipu std::meta::info. Šī vērtība pastāv tikai kompilēšanas laikā un apraksta attiecīgo elementu. Otrā ir splice sintakse [: ... :], kas darbojas pretējā virzienā: no std::meta::info vērtības atpakaļ uzģenerē reālu kodu.
Praktisks piemērs — visu struktūras lauku uzskaitīšana:
constexpr auto members = std::meta::nonstatic_data_members_of(^^Point);
Šeit ^^Point atgriež struktūras Point aprakstu, un nonstatic_data_members_of no tā izvelk visu lauku sarakstu. Ar splice operatoru pār šo sarakstu var iterēt un katram laukam uzģenerēt kodu. Viss notiek pirms programma vispār sāk darboties, tāpēc darbības laikā papildu izmaksu nav — ar to C++ refleksija atšķiras no Java un C#, kur refleksija strādā programmas izpildes laikā.
Tāpat var nolasīt enum vērtību nosaukumus. Funkcija std::meta::enumerators_of(^^Krāsa) atdod visu enum konstantu sarakstu, un ar std::meta::identifier_of katrai no tām var iegūt nosaukumu kā virkni. No tā kompilators pats sagatavo tabulu, kas skaitlisko vērtību pārvērš tekstā. Agrāk to pašu vajadzēja rakstīt ar roku vai ģenerēt no ārpuses, un pievienojot enum jaunu vērtību, tabulu bija viegli aizmirst atjaunināt.
Kāpēc izstrādātājiem tas ir svarīgi
Vairākas ikdienas problēmas, ko līdz šim risināja ar apgrūtinošiem apvedceļiem, tagad atrisina dažas rindiņas. Enum vērtības pārvēršana par teksta virkni C++ ilgi prasīja vai nu makro triku, vai atsevišķu skriptu; ar refleksiju kompilators to izdara pats. Serializācijas bibliotēkas var pašas atrast struktūras laukus, tāpēc lauka pārsaukšana automātiski atspoguļojas kartējumā, nevis rada kluso kļūdu. Tie paši principi attiecas uz ORM kartētājiem un atkarību ievadīšanas ietvariem, kas līdz šim balstījās uz gariem makro sarakstiem.
Ir arī ieguvums būvēšanas ķēdē. Daudzos lielos projektos struktūru un enum aprakstus līdz šim ģenerēja atsevišķs solis pirms kompilēšanas — parasti Python skripts vai īpašs rīks, kas nolasīja galvenes un izrakstīja papildu C++ failus. Ar refleksiju šo soli var izlaist, jo kompilatoram vairs nav vajadzīga ārēja palīdzība, lai uzzinātu tipa uzbūvi. Mazāk kustīgo daļu būvēšanas skriptā nozīmē arī mazāk vietu, kur tas var salūzt.
Firmas Whole Tomato apskatā par lielām kodbāzēm norādīts, ka galvenais atklātais jautājums ir kompilēšanas laiks — refleksija visu darbu pārceļ uz kompilatoru, un cik tas palēnina lielu projektu būvēšanu, vēl nav pietiekami izmērīts. Produkcijas mērījumu joprojām ir maz.
Standarts pabeigts, bet ne bez strīda
C++26 komiteja martā apstiprināja arī līgumus (contracts) — priekšlikumu P2900, kas valodai pievieno priekšnosacījumus, pēcnosacījumus un jaunu apgalvojuma formu. Balsojums bija 114 par, 12 pret un trīs atturējās. Daļa komitejas locekļu iebilda pret līgumu tehnisko risinājumu, un The Register ziņoja par nesaskaņām jau pirms galīgā balsojuma. Neatkarīgi no iebildumiem līgumi tagad ir standarta daļā.
Blakus refleksijai un līgumiem C++26 ienesa arī drošības uzlabojumus. Viens no tiem — P2795 — nosaka, ka neinicializēta mainīgā nolasīšana turpmāk ir kļūdaina uzvedība ar definētu iznākumu, nevis pilnīgi neparedzama darbība, kā līdz šim.
Kur stāv kompilatoru atbalsts
GCC 16.1 refleksiju ieslēdz ar -freflection, un līdztekus P2996 tas iekļauj arī anotācijas, funkciju parametru refleksiju un paplašinājuma priekšrakstus. Šajā laidienā GCC pēc noklusējuma pārgāja uz C++20; C++26 iespējas vēl jāieslēdz ar tiešu karodziņu. Header fails joprojām saucas <experimental/meta>, kas norāda uz to, ka realizācija vēl ir eksperimentāla.
Otra pilnīgākā realizācija ir Bloomberg atvērtā koda clang-p2996 dakša, kas kalpoja par atsauces implementāciju P2996 izstrādes laikā. EDG kompilators arī realizē refleksiju, un abus var izmēģināt Compiler Explorer vietnē. Microsoft Visual C++ refleksiju publiski neatbalsta un nav paziņojis termiņu — tas nozīmē, ka Windows izstrādātāji, kas balstās uz MSVC, uz šo iespēju pagaidām gaida.
Praksē tas rada zināmu plaisu: koda līmenī refleksija ir standarta daļa, bet reāli to var lietot tikai tur, kur būvēšanai izmanto GCC vai clang dakšu. Portablu bibliotēku autoriem tas nozīmē, ka refleksijas kodu vēl kādu laiku nāksies turēt aiz nosacīta kompilēšanas slēdža.
Komentāri
Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.