C++23 adalah standar yang terbit paling baru (disahkan ISO 2024), dan pilihannya sangat pragmatis: fitur-fiturnya ditujukan untuk kode sehari-hari, bukan untuk paradigma baru. std::print mengakhiri era std::cout << ... << ... untuk keluaran berformat; std::expected memberi cara standar mengembalikan nilai atau galat tanpa exception; deducing this menyederhanakan duplikasi method const/non-const; subscript multidimensi membuat m[i, j] legal; std::generator membuat coroutine layak pakai tanpa menulis promise type sendiri; dan static operator() mempercepat pemanggilan fungsi objek. Standar ini adalah target penuh toolchain kita (g++ 14.2), sehingga semua contoh di chapter ini benar-benar kita jalankan.

Program Demo Fitur C++23 #

cpp
// fitur-cpp23.cpp — C++23: print, expected, deducing this, generator, dan lainnya
// Kompilasi: g++ -std=c++23 -Wall -Wextra fitur-cpp23.cpp -o fitur23

#include <expected>
#include <generator>
#include <print>
#include <ranges>
#include <string>

// deducing this (C++23): parameter objek eksplisit, satu versi untuk semua cv
struct Kotak {
    int isi = 0;

    void lihat(this const Kotak& self) {
        std::print("isi = {}\n", self.isi);
    }
    void ubah(this Kotak& self, int nilaiBaru) {
        self.isi = nilaiBaru;
    }
};

// static operator() (C++23): call operator tanpa instance
struct Penjumlah {
    static int operator()(int a, int b) { return a + b; }
};

// multidimensional subscript (C++23): operator[] dua indeks
struct Matriks2x2 {
    int data[4] = {};

    int& operator[](std::size_t baris, std::size_t kolom) {
        return data[baris * 2 + kolom];
    }
    int operator[](std::size_t baris, std::size_t kolom) const {
        return data[baris * 2 + kolom];
    }
};

// std::generator (C++23): coroutine siap pakai untuk deret malas
std::generator<int> fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield a;
        int berikut = a + b;
        a = b;
        b = berikut;
    }
}

// std::expected (C++23): hasil atau galat, tanpa exception
std::expected<int, std::string> bagi(int a, int b) {
    if (b == 0) {
        return std::unexpected(std::string("pembagi nol"));
    }
    return a / b;
}

int main() {
    std::print("mulai program\n");

    Kotak k{.isi = 7};
    k.lihat();
    k.ubah(9);
    k.lihat();

    Penjumlah tambah;
    std::print("Penjumlah: {}\n", tambah(2, 3));

    Matriks2x2 m;
    m[0, 0] = 5;
    m[1, 1] = 8;
    std::print("m[0,0]={} m[1,1]={}\n", m[0, 0], m[1, 1]);

    for (int f : fibonacci() | std::views::take(8)) {   // generator + view
        std::print("{} ", f);
    }
    std::print("\n");

    std::print("10/4 = {}\n", bagi(10, 4).value_or(-1));
    auto gagal = bagi(10, 0);
    if (!gagal) {
        std::print("gagal: {}\n", gagal.error());
    }
    int lanjutan = bagi(9, 3)
        .and_then([](int v) -> std::expected<int, std::string> { return v * 100; })
        .value_or(-1);
    std::print("9/3 x100 = {}\n", lanjutan);

    if consteval {                       // jalur compile time vs runtime
        std::print("dihitung saat kompilasi\n");
    } else {
        std::print("dihitung saat runtime\n");
    }
    return 0;
}

Output yang Dihasilkan:

text
mulai program
isi = 7
isi = 9
Penjumlah: 5
m[0,0]=5 m[1,1]=8
0 1 1 2 3 5 8 13 
10/4 = 2
gagal: pembagi nol
9/3 x100 = 300
dihitung saat runtime

Mari kita bedah:

  1. Baris 14-19 (deducing this): parameter pertama ditulis eksplisit — this const Kotak& self untuk baca, this Kotak& self untuk ubah. compiler menyimpulkan tipe this sesuai konteks pemanggil, sehingga satu template bisa melayani versi lvalue, rvalue, const, dan non-const tanpa duplikasi.
  2. Baris 23-25 (static operator()): Penjumlah::operator() statis — dipanggil lewat objek tambah(2, 3) namun tidak menyentuh state, sehingga tidak perlu instance yang memuat data dan pemanggilannya lebih murah.
  3. Baris 28-37 (multidimensional subscript): m[0, 0] dan m[1, 1] memanggil operator[](baris, kolom) dengan dua argumen — sebelum C++23, operator[] hanya boleh satu parameter sehingga class matriks terpaksa pakai operator().
  4. Baris 40-48 (std::generator): fungsi biasa yang berisi co_yield otomatis menjadi coroutine; fibonacci() bisa diiterasi seperti container dan bahkan dirangkai dengan views::take(8). Delapan angka pertama tercetak: 0 1 1 2 3 5 8 13.
  5. Baris 51-56 (std::expected): kembalian expected<int, string> berisi nilai ATAU galat. std::unexpected membungkus galat; value_or(-1) membaca nilai dengan cadangan aman; error() membaca pesan galat.
  6. Baris 84-87 (monadic and_then): and_then merantai operasi hanya bila nilai sukses — pola ini menggantikan sarang if (ok) berlapis.
  7. Baris 89-93 (if consteval): memeriksa “apakah dievaluasi saat kompilasi?”; program ini dijalankan saat runtime, jadi cabang else yang tercetak.

std::mdspan: Jendela Multidimensi #

Teman sekelas std::span, std::mdspan memberi view multidimensi (baris-kolom-tensor) ke data kontigu tanpa memiliki datanya — ideal untuk membungkus buffer matriks tanpa menyalin:

cpp Ilustrasi std::mdspan (butuh dukungan <mdspan>)
#include <mdspan>

int data[6] = {1, 2, 3, 4, 5, 6};
std::mdspan m(data, 2, 3);       // view 2x3 ke array yang sama
std::println("{}", m[1, 2]);     // elemen baris 1 kolom 2 -> 6

Pada toolchain course ini (g++ 14.2), header <mdspan> belum tersedia sehingga contoh di atas hanya ilustrasi — lihat tabel dukungan compiler di cppreference . Konsepnya tetap penting: mdspan adalah span untuk dimensi lebih dari satu.

C++23 menutup banyak permintaan praktis dan, seperti C++14, sifatnya pemoles — tetapi pemoles yang mengubah kebiasaan: setelah terbiasa std::print dan std::expected, kembali ke std::cout dan exception terasa melelahkan. Chapter berikutnya melihat ke depan: apa saja isi C++26 dan bagaimana kita mengecek dukungan compiler untuk fitur yang belum stabil.

Rujukan resmi: cppreference — fitur C++23 , cppreference — std::expected , cppreference — std::generator .