consteval ve constinit (C++20)
Bir pastane düşün. Bazı pastalar önceden yapılıp vitrinde bekler — müşteri geldiğinde doğrudan teslim edilir. Bazıları ise sipariş üzerine yapılır, beklemek gerekir. constexpr pastanın "önceden yapılabilir ama sipariş üzerine de yapılabilir" demesi gibiydi. C++20 ile gelen consteval ve constinit ise daha kesin garantiler veriyor: consteval "bu pasta SADECE önceden yapılır, asla sipariş üzerine yapılmaz" demek; constinit ise "vitrine konan pasta kesinlikle başlangıçta hazır olacak, sonradan konmayacak" garantisi. Bu nüanslar küçük görünebilir ama büyük projelerde derleme zamanı güvenliği ve başlatma sırası sorunlarını çözmenin anahtarıdır.
constexpr Tekrarı: İki Yüzlü Fonksiyon
constexpr C++11'de geldi ve "bu fonksiyon derleme zamanında hesaplanabilir" anlamına geliyordu. Ama kritik nokta şu: hesaplanabilir, hesaplanmak zorunda değil.
#include <iostream>
#include <cstdint>
constexpr uint64_t factorial(int n) {
uint64_t result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
int main() {
// Derleme zamanında hesaplanır (constexpr context)
constexpr auto compile_time = factorial(10);
// Çalışma zamanında hesaplanır (runtime context)
int n;
std::cout << "Sayi girin: ";
std::cin >> n;
auto runtime = factorial(n); // Kullanıcı girdisi → derleme zamanı mümkün değil
std::cout << "10! = " << compile_time << "\n";
std::cout << n << "! = " << runtime << "\n";
return 0;
}factorial fonksiyonu constexpr olmasına rağmen, argüman çalışma zamanında belirleniyorsa çalışma zamanında hesaplanır. Bu esneklik genellikle iyidir ama bazen sorun yaratır: "bu fonksiyon kesinlikle derleme zamanında çalışsın" diyemiyorsun. Yanlışlıkla runtime'a kayması, performans kaybı veya güvenlik açığı olabilir.
consteval: SADECE Derleme Zamanı
consteval (C++20), fonksiyonu immediate function olarak işaretler. Bu fonksiyon yalnızca derleme zamanında çalışabilir. Runtime'da çağrılmaya çalışılırsa derleme hatası alırsın.
#include <iostream>
#include <cstdint>
#include <array>
// consteval: Sadece derleme zamanında çalışır
consteval uint64_t compile_factorial(int n) {
uint64_t result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
// constexpr: Derleme veya çalışma zamanı
constexpr uint64_t flexible_factorial(int n) {
uint64_t result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
int main() {
// consteval — her ikisi de derleme zamanında
constexpr auto a = compile_factorial(10); // OK
auto b = compile_factorial(12); // OK — derleme zamanı sabiti
// Bu DERLEME HATASI verir:
// int n = 5;
// auto c = compile_factorial(n); // HATA! n derleme zamanı sabiti değil
// constexpr ile karşılaştır
int n = 5;
auto d = flexible_factorial(n); // OK — runtime'da çalışır
std::cout << "10! = " << a << "\n";
std::cout << "12! = " << b << "\n";
std::cout << "5! = " << d << "\n";
return 0;
}compile_factorial(n) satırını açarsan derleyici hata verir çünkü n bir runtime değişkeni. Bu tam da istenen davranış: "bu hesaplama derleme zamanında yapılmalı" demek istiyorsan, consteval bunu garanti eder.
constexpr vs consteval Özet
| Özellik | constexpr | consteval |
|---|---|---|
| Derleme zamanı | ✅ Yapabilir | ✅ Yapmak ZORUNDA |
| Çalışma zamanı | ✅ Yapabilir | ❌ Derleme hatası |
| C++ versiyonu | C++11 | C++20 |
| Kullanım | Esnek fonksiyonlar | Compile-time garanti |
consteval Use Case'leri
1. Compile-Time Validation
Derleme zamanında değer doğrulama, hatalı değerlerin runtime'a ulaşmasını engeller.
#include <iostream>
#include <cstdint>
#include <stdexcept>
// Port numarası doğrulama — derleme zamanında
consteval uint16_t validated_port(int port) {
if (port < 1 || port > 65535) {
throw "Port numarasi 1-65535 araliginda olmali"; // Derleme hatası
}
if (port < 1024) {
throw "Privileged port kullanmak icin root yetkisi gerekir";
}
return static_cast<uint16_t>(port);
}
// Renk kodu doğrulama
consteval uint32_t validated_color(uint32_t rgb) {
if (rgb > 0xFFFFFF) {
throw "Renk kodu 0x000000-0xFFFFFF araliginda olmali";
}
return rgb;
}
// Yüzde değer doğrulama
consteval double validated_percentage(double value) {
if (value < 0.0 || value > 100.0) {
throw "Yuzde 0-100 araliginda olmali";
}
return value / 100.0; // 0.0-1.0 aralığına normalize et
}
int main() {
// Doğru kullanımlar — derleme zamanında doğrulanır
constexpr auto http_port = validated_port(8080);
constexpr auto bg_color = validated_color(0x1A1A2E);
constexpr auto tax_rate = validated_percentage(18.0);
// Bu satırlar DERLEME HATASI verir:
// constexpr auto bad_port = validated_port(99999); // Port aralık dışı
// constexpr auto bad_color = validated_color(0x1FFFFFF); // Geçersiz renk
// constexpr auto bad_pct = validated_percentage(150.0); // %150?
std::cout << "HTTP Port: " << http_port << "\n";
std::cout << "Renk: 0x" << std::hex << bg_color << "\n";
std::cout << "Vergi orani: " << std::dec << tax_rate << "\n";
return 0;
}Buradaki güç, geçersiz değerlerin asla çalışan programda yer alamaması. Runtime'da if (port > 65535) kontrolü yazmayı unutabilirsin ama consteval fonksiyondaki throw, derleme zamanında tetiklenir ve hata mesajı olarak görünür.
2. Lookup Table (LUT) Generation
Derleme zamanında hesaplanan tablolar, runtime'da sıfır maliyetle kullanılır.
#include <iostream>
#include <array>
#include <cstdint>
#include <cmath>
// Derleme zamanı sin tablosu oluştur (0-359 derece)
consteval auto generate_sin_table() {
std::array<double, 360> table{};
for (int i = 0; i < 360; ++i) {
// consteval içinde cmath kullanılamayabilir,
// Taylor serisi ile hesapla
double radians = i * 3.14159265358979323846 / 180.0;
// sin(x) Taylor serisi: x - x³/3! + x⁵/5! - x⁷/7! + ...
double x = radians;
// Normalize to [-π, π]
while (x > 3.14159265358979323846) x -= 2 * 3.14159265358979323846;
while (x < -3.14159265358979323846) x += 2 * 3.14159265358979323846;
double term = x;
double sum = x;
for (int n = 1; n <= 10; ++n) {
term *= -x * x / ((2.0 * n) * (2.0 * n + 1));
sum += term;
}
table[i] = sum;
}
return table;
}
// CRC32 lookup table
consteval auto generate_crc32_table() {
std::array<uint32_t, 256> table{};
for (uint32_t i = 0; i < 256; ++i) {
uint32_t crc = i;
for (int j = 0; j < 8; ++j) {
if (crc & 1) {
crc = (crc >> 1) ^ 0xEDB88320;
} else {
crc >>= 1;
}
}
table[i] = crc;
}
return table;
}
// Tablolar binary'ye gömülür — runtime maliyeti sıfır
constexpr auto SIN_TABLE = generate_sin_table();
constexpr auto CRC32_TABLE = generate_crc32_table();
// Hızlı sin lookup (derleme zamanında oluşturulan tablodan)
double fast_sin(int degrees) {
int normalized = ((degrees % 360) + 360) % 360;
return SIN_TABLE[normalized];
}
// CRC32 hesaplama (derleme zamanında oluşturulan tablodan)
uint32_t crc32(const char* data, size_t length) {
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < length; ++i) {
uint8_t byte = static_cast<uint8_t>(data[i]);
crc = (crc >> 8) ^ CRC32_TABLE[(crc ^ byte) & 0xFF];
}
return crc ^ 0xFFFFFFFF;
}
int main() {
// Sin tablosu kullanımı
std::cout << "sin(0) = " << fast_sin(0) << "\n";
std::cout << "sin(30) = " << fast_sin(30) << "\n";
std::cout << "sin(90) = " << fast_sin(90) << "\n";
std::cout << "sin(180) = " << fast_sin(180) << "\n";
// CRC32 kullanımı
const char* msg = "Hello, World!";
std::cout << "\nCRC32(\"" << msg << "\") = 0x"
<< std::hex << crc32(msg, 13) << "\n";
return 0;
}Her iki tablo da consteval fonksiyonlarla derleme zamanında hesaplanıyor. Binary'ye sabit veri olarak gömülüyor. Runtime'da tek bir hesaplama yok — sadece tablo lookup.
⚠️ Dikkat: consteval fonksiyon içinde kullanabileceğin işlemler sınırlıdır. Dinamik bellek tahsisi (C++20'de constexpr new kısmen destekleniyor), I/O, ve bazı standart kütüphane fonksiyonları kullanılamaz. Bu yüzden sin tablosu örneğinde std::sin() yerine Taylor serisi kullandık.
constinit: Static Storage Garantisi
constinit, değişkenin derleme zamanında başlatılmasını garanti eder. Ama constexpr'den farklı olarak, değişkenin sonradan değiştirilmesine izin verir.
#include <iostream>
#include <string>
// constexpr: Başlatma derleme zamanında + değer asla değişmez
constexpr int MAX_USERS = 1000;
// MAX_USERS = 2000; // HATA! constexpr değişken değiştirilemez
// constinit: Başlatma derleme zamanında + sonradan değiştirilebilir
constinit int current_user_count = 0; // Derleme zamanında 0 ile başlatılır
// constinit sadece static/thread_local storage duration ile kullanılır
constinit static double pi_approx = 3.14159;
constinit thread_local int thread_counter = 0;
void add_user() {
++current_user_count; // OK — constinit başlatmayı garanti eder, immutable yapmaz
++thread_counter;
}
int main() {
std::cout << "Başlangıç: " << current_user_count << " kullanici\n";
add_user();
add_user();
add_user();
std::cout << "Simdi: " << current_user_count << " kullanici\n";
// Bu DERLEME HATASI verir:
// constinit int local_var = 42; // HATA! Local variable static storage değil
// Bu da HATA verir:
// constinit int runtime_init = some_runtime_function(); // Derleme zamanı değil!
return 0;
}constinit ile constexpr farkını anlamak kritik:
| Özellik | constexpr değişken | constinit değişken |
|---|---|---|
| Derleme zamanında başlatma | ✅ Zorunlu | ✅ Zorunlu |
| Sonradan değiştirilebilir | ❌ Hayır (const) | ✅ Evet |
| Local variable olabilir | ✅ Evet | ❌ Sadece static/thread_local |
| Amaç | Compile-time sabit | Güvenli başlatma garantisi |
Static Initialization Order Fiasco
constinit'in varlık sebebi, C++'ın en eski ve en sinsi sorunlarından birini çözmektir: Static Initialization Order Fiasco.
Problem
Farklı translation unit'lerdeki (farklı .cpp dosyaları) global değişkenlerin başlatma sırası tanımsızdır. Standart, aynı dosyadaki global değişkenlerin yukarıdan aşağıya başlatılacağını garanti eder ama dosyalar arası sıra belirsizdir.
// ---- config.cpp ----
#include <string>
// Bu global, runtime'da başlatılır (string constructor çalışır)
std::string app_name = "MyApp";
int max_connections = 100;
// ---- logger.cpp ----
#include <string>
#include <iostream>
extern std::string app_name; // config.cpp'den
// SORUN: app_name başlatılmış mı, başlatılmamış mı?
// logger.cpp, config.cpp'den önce başlatılırsa → boş string!
std::string log_prefix = "[" + app_name + "] ";
// ---- main.cpp ----
#include <iostream>
extern std::string log_prefix;
int main() {
// log_prefix "[]" olabilir! (app_name henüz başlatılmamışsa)
// Ya da "[MyApp]" olabilir. Tanımsız davranış değil ama tanımsız sıra.
std::cout << log_prefix << "Uygulama başlatıldı\n";
return 0;
}Bu sorun her zaman ortaya çıkmaz. Belki yüzlerce build'de doğru çalışır, sonra derleyici güncellenir veya link sırası değişir ve bir gece 3'te uygulamam çöker. Debugging kabusu.
constinit ile Çözüm
// ---- config.cpp ----
#include <cstdint>
// constinit: Derleme zamanında başlatılır — sıra sorunu yok
constinit int32_t max_connections = 100;
constinit double timeout_seconds = 30.0;
constinit bool debug_mode = false;
// String constinit olamaz (std::string runtime constructor gerektirir)
// Ama const char* olabilir:
constinit const char* app_name = "MyApp";
constinit const char* version = "2.1.0";
// ---- logger.cpp ----
#include <iostream>
extern constinit const char* app_name;
extern constinit bool debug_mode;
void log_message(const char* msg) {
// app_name kesinlikle başlatılmış — constinit garantisi
std::cout << "[" << app_name << "] " << msg << "\n";
}
void log_debug(const char* msg) {
if (debug_mode) { // debug_mode kesinlikle başlatılmış
std::cout << "[DEBUG] " << msg << "\n";
}
}
// ---- main.cpp ----
extern constinit int32_t max_connections;
extern constinit const char* app_name;
int main() {
// Tüm constinit değişkenler güvenli — sıra sorunu yok
std::cout << "Uygulama: " << app_name << "\n";
std::cout << "Max bağlantı: " << max_connections << "\n";
log_message("Başlatıldı");
return 0;
}constinit değişkenler zero initialization veya constant initialization ile başlatılır — bu, herhangi bir dynamic initialization'dan (constructor çağrıları) önce gerçekleşir. Böylece sıra sorunu ortadan kalkar.
Alternatif Çözümler
constinit öncesinde (veya constinit kullanamadığın durumlarda) fiasco'yu çözmenin klasik yolları:
#include <iostream>
#include <string>
// Çözüm 1: Meyers Singleton (fonksiyon-local static)
// İlk çağrıda başlatılır, sıra sorunu yok
std::string& get_app_name() {
static std::string name = "MyApp"; // İlk çağrıda oluşur
return name;
}
// Çözüm 2: Pointer + lazy init
class Database {
public:
static Database& instance() {
static Database db; // Thread-safe (C++11 garantisi)
return db;
}
private:
Database() { std::cout << "DB başlatıldı\n"; }
};
int main() {
// get_app_name() çağrıldığında kesinlikle başlatılmış
std::cout << get_app_name() << "\n";
auto& db = Database::instance();
return 0;
}Ama Meyers Singleton pattern'ı constinit'e göre dezavantajlıdır: fonksiyon çağrısı gerektirir, daha fazla boilerplate ve ilk çağrıda thread-safe başlatma maliyeti.
constexpr vs consteval vs constinit — Büyük Karşılaştırma
constexpr | consteval | constinit | |
|---|---|---|---|
| Ne için? | Fonksiyon veya değişken | Sadece fonksiyon | Sadece değişken |
| Derleme zamanı | Yapabilir | Yapmak ZORUNDA | Başlatma zorunlu |
| Çalışma zamanı | Yapabilir | ❌ Derleme hatası | Değiştirilebilir |
| const mu? | Değişken ise evet | N/A | ❌ Hayır |
| Storage | Herhangi | N/A | static / thread_local |
| C++ versiyonu | C++11 | C++20 | C++20 |
| Ana kullanım | Esnek hesaplama | Compile-time garanti | Güvenli başlatma |
Karar Ağacı
Derleme zamanında hesaplama mı?
├── Evet, fonksiyon mu?
│ ├── Hem derleme hem runtime'da çalışabilir mi? → constexpr
│ └── SADECE derleme zamanı mı? → consteval
└── Evet, değişken mi?
├── Asla değişmeyecek sabit mi? → constexpr
└── Başlatma güvenliği + sonradan değişebilir mi? → constinitPratik Örnekler
Derleme Zamanı Hash
String'lerin derleme zamanında hash'lenmesi, runtime'da string karşılaştırma yerine integer karşılaştırma yapılmasını sağlar.
#include <iostream>
#include <cstdint>
#include <string_view>
// FNV-1a hash — derleme zamanında hesaplanan string hash
consteval uint64_t compile_time_hash(std::string_view str) {
uint64_t hash = 14695981039346656037ULL; // FNV offset basis
for (char c : str) {
hash ^= static_cast<uint64_t>(c);
hash *= 1099511628211ULL; // FNV prime
}
return hash;
}
// Runtime hash (aynı algoritma)
uint64_t runtime_hash(std::string_view str) {
uint64_t hash = 14695981039346656037ULL;
for (char c : str) {
hash ^= static_cast<uint64_t>(c);
hash *= 1099511628211ULL;
}
return hash;
}
// Switch-case ile string matching (hash tabanlı)
void handle_command(std::string_view cmd) {
// Derleme zamanı hash'ler — consteval garanti eder
constexpr auto HASH_HELP = compile_time_hash("help");
constexpr auto HASH_QUIT = compile_time_hash("quit");
constexpr auto HASH_LIST = compile_time_hash("list");
constexpr auto HASH_ADD = compile_time_hash("add");
constexpr auto HASH_DEL = compile_time_hash("delete");
switch (runtime_hash(cmd)) {
case HASH_HELP:
std::cout << "Yardım menüsü gösteriliyor...\n";
break;
case HASH_QUIT:
std::cout << "Çıkılıyor...\n";
break;
case HASH_LIST:
std::cout << "Liste gösteriliyor...\n";
break;
case HASH_ADD:
std::cout << "Ekleme modu...\n";
break;
case HASH_DEL:
std::cout << "Silme modu...\n";
break;
default:
std::cout << "Bilinmeyen komut: " << cmd << "\n";
}
}
int main() {
// Derleme zamanı hash değerlerini göster
std::cout << "Hash('help') = " << compile_time_hash("help") << "\n";
std::cout << "Hash('quit') = " << compile_time_hash("quit") << "\n";
// Komutları işle
handle_command("help");
handle_command("list");
handle_command("quit");
handle_command("bilinmeyen");
return 0;
}consteval burada kritik: case label'ları derleme zamanı sabiti olmak zorunda. constexpr de işe yarar ama consteval niyeti daha açık ifade eder ve yanlışlıkla runtime'a kayma ihtimalini sıfırlar.
Config Validation
Compile-time configuration doğrulama, yanlış konfigürasyonla çalıştırılabilir dosya üretilmesini engeller.
#include <iostream>
#include <cstdint>
// Derleme zamanında config doğrulama
struct AppConfig {
int32_t port;
int32_t max_threads;
int32_t max_connections;
int32_t buffer_size;
double timeout;
};
consteval AppConfig make_validated_config(
int32_t port, int32_t threads, int32_t connections,
int32_t buffer_size, double timeout)
{
if (port < 1024 || port > 65535)
throw "Port 1024-65535 araliginda olmali";
if (threads < 1 || threads > 256)
throw "Thread sayisi 1-256 araliginda olmali";
if (connections < 1 || connections > 100000)
throw "Max baglanti 1-100000 araliginda olmali";
if (buffer_size < 512 || buffer_size > 1048576)
throw "Buffer boyutu 512-1MB araliginda olmali";
if (buffer_size & (buffer_size - 1))
throw "Buffer boyutu 2'nin kuvveti olmali";
if (timeout < 0.1 || timeout > 300.0)
throw "Timeout 0.1-300.0 saniye araliginda olmali";
if (connections > threads * 1000)
throw "Connection/thread orani cok yuksek (max 1000:1)";
return AppConfig{port, threads, connections, buffer_size, timeout};
}
// Config binary'ye gömülür — runtime maliyeti sıfır
constexpr auto CONFIG = make_validated_config(
8080, // port
16, // threads
10000, // max connections
4096, // buffer size (4KB)
30.0 // timeout
);
// Hatalı config — derleme hatası verir:
// constexpr auto BAD = make_validated_config(80, 16, 10000, 4096, 30.0);
// → "Port 1024-65535 araliginda olmali"
// constexpr auto BAD2 = make_validated_config(8080, 16, 10000, 3000, 30.0);
// → "Buffer boyutu 2'nin kuvveti olmali"
int main() {
std::cout << "Port: " << CONFIG.port << "\n";
std::cout << "Threads: " << CONFIG.max_threads << "\n";
std::cout << "Max Connections: " << CONFIG.max_connections << "\n";
std::cout << "Buffer Size: " << CONFIG.buffer_size << "\n";
std::cout << "Timeout: " << CONFIG.timeout << "s\n";
return 0;
}Tüm validasyon derleme zamanında gerçekleşiyor. Hatalı config ile binary oluşturmak imkansız. Runtime'da hiçbir kontrol gerekmez, hiçbir if yazılmaz — güvenlik bedava.
💡 İpucu: consteval fonksiyonda throw kullanımı özel: runtime'da asla çalışmayacağı için gerçekte exception fırlatılmaz. Derleyici, throw'a ulaşan bir code path tespit ederse bunu derleme hatası olarak raporlar. Bu, derleme zamanı hata mesajı oluşturmanın zekice bir yoludur.
consteval ile is_constant_evaluated Etkileşimi
C++20 ayrıca std::is_constant_evaluated() fonksiyonunu sunar. Bu, constexpr fonksiyonların derleme vs çalışma zamanında farklı davranmasını sağlar. Ama consteval fonksiyonlarda her zaman true döner — çünkü zaten sadece derleme zamanında çalışır.
#include <iostream>
#include <type_traits>
constexpr int smart_compute(int x) {
if (std::is_constant_evaluated()) {
// Derleme zamanı: basit ama güvenli yol
int result = 0;
for (int i = 0; i < x; ++i) result += i;
return result;
} else {
// Çalışma zamanı: optimize edilmiş formül
return x * (x - 1) / 2;
}
}
consteval int always_compile_time(int x) {
// std::is_constant_evaluated() burada her zaman true
// Çünkü consteval fonksiyon zaten sadece derleme zamanında çalışır
return x * (x - 1) / 2;
}
int main() {
constexpr auto a = smart_compute(100); // Derleme zamanı yolu
int n = 100;
auto b = smart_compute(n); // Çalışma zamanı yolu
constexpr auto c = always_compile_time(100); // Her zaman derleme zamanı
std::cout << "a = " << a << "\n";
std::cout << "b = " << b << "\n";
std::cout << "c = " << c << "\n";
return 0;
}Yaygın Hatalar ve Dikkat Edilecekler
consteval Fonksiyona Pointer Alınamaz
consteval int square(int x) { return x * x; }
int main() {
// DERLEME HATASI — consteval fonksiyona pointer alınamaz
// auto fn_ptr = □
// constexpr fonksiyona pointer alınabilir (runtime'da çağrılır)
constexpr auto sq = square(5); // OK — doğrudan çağrı
return 0;
}Mantıklı: fonksiyon pointer'ı runtime'da çağrılmak içindir ama consteval fonksiyon runtime'da çalışamaz.
constinit ve const Birlikte
// constinit + const = derleme zamanında başlatılan, değiştirilemeyen değer
// constexpr ile neredeyse aynı — ama constexpr'den farklı olarak
// constinit const, non-literal tipler için de çalışabilir (eğer başlatıcı constexpr ise)
constinit const int MAX_SIZE = 1024; // OK
constinit int mutable_counter = 0; // OK, sonradan değiştirilebilir
// constinit auto ile
constinit const auto TIMEOUT = 30.0; // OKconsteval İçinde Kısıtlamalar
// consteval fonksiyonlarda yapılamayacaklar:
// 1. I/O işlemleri (std::cout, dosya okuma)
// 2. reinterpret_cast
// 3. inline assembly
// 4. Undefined behavior (herhangi bir UB derleme hatası verir!)
// 5. Bazı standart kütüphane fonksiyonları
// Bu AVANTAJ: consteval, UB'yi derleme zamanında yakalar
consteval int safe_divide(int a, int b) {
// b == 0 ise → UB → derleme hatası!
return a / b;
}
// constexpr auto oops = safe_divide(10, 0); // Derleme hatası: UB tespit edildi⚠️ Dikkat: consteval (ve constexpr) fonksiyonlarda undefined behavior her zaman derleme hatasıdır. Bu, UB'nin "sessizce çalışıp sonra crash eden" normal davranışından çok farklı ve çok faydalıdır. Sıfıra bölme, out-of-bounds erişim, signed overflow — hepsi derleme zamanında yakalanır.
Özet
`constexpr` fonksiyon esnektir — derleme zamanında çalışabilir ama çalışma zamanına da kayabilir. Değişken olarak kullanıldığında ise her zaman sabittir.
`consteval` (C++20) fonksiyonu sadece derleme zamanında çalışır — runtime çağrısı derleme hatası verir. Compile-time validation, LUT generation ve hash hesaplama için idealdir.
`constinit` (C++20) değişkenin derleme zamanında başlatılmasını garanti eder ama sonradan değiştirilmesine izin verir — static/thread_local storage duration ile kullanılır.
Static Initialization Order Fiasco, farklı dosyalardaki global değişkenlerin belirsiz başlatma sırasından kaynaklanan sinsi bir sorundur —
constinitbu sorunu kökünden çözer.`consteval` fonksiyondaki `throw`, derleme zamanı hata mesajı üretmenin zarif bir yoludur — geçersiz config veya parametre derleme hatası olarak yakalanır.
UB tespiti
consteval'in gizli süper gücüdür — sıfıra bölme, overflow gibi sorunlar derleme zamanında garantili olarak yakalanır.
AI Asistan
Sorularını yanıtlamaya hazır