Setelah C++14 yang bertugas memoles, C++17 kembali menjadi standar besar dengan satu tema: menghilangkan jembatan keledai antara apa yang ingin kita tulis dan apa yang harus kita tulis. Deklarasi std::map<std::string, int>::value_type::second_type::type digantikan structured bindings; template rekursif untuk penjumlahan variadic digantikan fold expression; pola “parameter keluaran” digantikan std::optional; tag dispatch yang penuh boilerplate digantikan if constexpr; dan variabel global di header tidak lagi butuh trik inline pada variabel — kini inline variable resmi. Ditambah [[nodiscard]] dan std::string_view, C++17 memberi perangkat yang akan terus kita pakai di section ini.

Program Demo Fitur C++17 #

Berikut satu file yang memuat sembilan fitur C++17, dikompilasi -std=c++17.

cpp
// fitur-cpp17.cpp — C++17: sintaks lebih ringkas dan tipe utilitas baru
// Kompilasi: g++ -std=c++17 -Wall -Wextra fitur-cpp17.cpp -o fitur17

#include <any>
#include <iostream>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <variant>

// [[nodiscard]] (C++17): hasil yang diabaikan memicu peringatan compiler
[[nodiscard]] int hitungTotal(int a, int b) { return a + b; }

// fold expression (C++17): menjumlahkan semua argumen tanpa rekursi
template <typename... Args>
auto jumlahkan(Args... args) {
    return (args + ...);
}

// inline variable (C++17): satu definisi, aman di header
inline constexpr int VERSI = 17;

std::optional<std::string> cariNama(int id) {
    if (id == 1) {
        return std::string("Budi");
    }
    return std::nullopt;
}

int main() {
    std::map<std::string, int> stok{{"buku", 7}, {"pensil", 20}};
    for (const auto& [nama, jumlah] : stok) {     // structured bindings
        std::cout << nama << "=" << jumlah << "\n";
    }

    constexpr int mode = 2;
    if constexpr (mode == 1) {                    // if constexpr
        std::cout << "mode satu\n";
    } else if constexpr (mode == 2) {
        std::cout << "mode dua\n";
    } else {
        std::cout << "mode lain\n";
    }

    if (int total = jumlahkan(1, 2, 3, 4); total > 5) {  // if + initializer
        std::cout << "total=" << total << "\n";
    }

    std::optional<int> nilai = 42;
    std::cout << nilai.value_or(0) << "\n";

    std::variant<int, std::string> identitas = std::string("budi");
    std::visit([](const auto& isi) { std::cout << isi << "\n"; }, identitas);

    std::any lampiran = 3.14;
    std::cout << std::any_cast<double>(lampiran) << "\n";

    std::string sumber = "halaman";
    std::string_view awalan = std::string_view(sumber).substr(0, 4);  // tanpa salinan
    std::cout << awalan << "\n";

    std::cout << VERSI << "\n";
    int hasil = hitungTotal(9, 8);   // [[nodiscard]] dipatuhi
    std::cout << hasil << "\n";
    return 0;
}

Output yang Dihasilkan:

text
buku=7
pensil=20
mode dua
total=10
42
budi
3.14
hala
17
17

Mari kita bedah:

  1. Baris 33-35 (structured bindings): iterasi map tanpa menyentuh first/second — nama dan jumlah adalah nama langsung untuk key dan value. Pasangan binding cukup: jumlah nama = jumlah elemen.
  2. Baris 37-44 (if constexpr): kondisi dievaluasi saat kompilasi; cabang yang gagal tidak dikompilasi sama sekali. Karena mode == 2, hanya mode dua yang tercetak — dan hanya cabang itu yang ada di binary.
  3. Baris 46-48 (if dengan initializer): variabel total lahir di dalam if dan mati setelahnya, sehingga tidak bocor ke scope luar. Pola ini menjaga scope variabel sekecil mungkin; switch punya bentuk yang sama.
  4. Baris 50-51 (std::optional): value_or(0) memberi bacaan aman — bila optional kosong, jawabannya 0. Ini pengganti idiom “kembalikan -1 sebagai penanda gagal”.
  5. Baris 53-54 (std::variant + std::visit): identitas berisi int atau std::string, dan visitor menangani tipe apa pun yang aktif tanpa cast manual.
  6. Baris 56-57 (std::any): wadah tipe apa pun dengan any_cast<double> untuk mengambil nilai — dipakai saat tipe benar-benar baru diketahui runtime.
  7. Baris 59-61 (string_view): substr(0, 4) pada std::string menyalin; pada std::string_view ia hanya menggeser pointer dan panjang — output hala tanpa satu alokasi pun.
  8. Baris 16-19 (fold expression): (args + ...) menerima 1, 2, 3, 4 dan menghasilkan 1+2+3+4 = 10. Versi C++11 membutuhkan rekursi dua template.
  9. Baris 22 + 63 (inline variable): inline constexpr int VERSI boleh didefinisikan di header; semua translation unit memakai satu entitas yang sama, bukan salinan terpisah.

[[nodiscard]]: Hasil yang Tidak Boleh Dibuang #

Fungsi hitungTotal (Baris 13) diberi [[nodiscard]]. Bila hasilnya diabaikan — misalnya seseorang menulis hitungTotal(9, 8); tanpa memakai nilainya — g++ 14.2 memperingatkan:

text Peringatan compiler bila hasil [[nodiscard]] diabaikan
warning: ignoring return value of ‘int hitungTotal(int, int)’, declared with attribute ‘nodiscard’ [-Wunused-result]

Atribut ini cocok untuk fungsi yang hasilnya satu-satunya alasan ia dipanggil: fungsi perhitungan, fungsi yang melaporkan keberhasilan, dan fungsi murni tanpa efek samping. Perhatikan Baris 64 mematuhi aturan itu dengan menyimpan hasilnya ke hasil.

C++17 menuntaskan banyak permintaan komunitas yang diundur sejak C++11, dan hasilnya terasa: kode modern yang kita tulis hari ini hampir selalu minimal C++17. Chapter berikutnya menaikkan target ke C++20 — standar dengan perubahan terbesar sejak C++11.

Rujukan resmi: cppreference — fitur C++17 , cppreference — structured binding declaration .