5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++17】構造化束縛とstd::optionalでコードがスッキリする

Last updated at Posted at 2025-12-25

はじめに

C++17は大型アップデートで、ものすごく便利な機能がたくさん追加された。

構造化束縛を使えるようになると、「C++17以前には戻れない」と思うようになるよ。

1. 構造化束縛

複数の値を一度に分解:

// ペア
pair<int, string> p = {42, "answer"};
auto [num, str] = p;

// タプル
tuple<int, double, string> t = {1, 3.14, "pi"};
auto [a, b, c] = t;

// 配列
int arr[] = {10, 20, 30};
auto [x, y, z] = arr;

// 構造体
struct Point { int x, y; };
auto [px, py] = Point{100, 200};

// mapのイテレーション
for (const auto& [key, value] : my_map) {
    cout << key << ": " << value << endl;
}

2. if constexpr

コンパイル時分岐:

template<typename T>
string type_name() {
    if constexpr (is_integral_v<T>) {
        return "integral";
    } else if constexpr (is_floating_point_v<T>) {
        return "floating point";
    } else {
        return "other";
    }
}

type_name<int>();    // "integral"
type_name<double>(); // "floating point"

3. if/switch 初期化文

スコープを限定した変数宣言:

// if文
if (auto it = m.find("key"); it != m.end()) {
    cout << it->second << endl;
}
// itはここでスコープ外

// switch文
switch (int val = compute(); val) {
    case 0: /* ... */ break;
    case 1: /* ... */ break;
}

4. std::optional

値があるかもしれない型:

#include <optional>

optional<int> find_value(vector<int>& vec, int target) {
    auto it = find(vec.begin(), vec.end(), target);
    if (it != vec.end()) return *it;
    return nullopt;
}

auto result = find_value(vec, 42);
if (result) {
    cout << *result << endl;
}

// デフォルト値
cout << result.value_or(-1) << endl;

// メソッド
result.has_value();  // 値があるか
result.reset();      // 値をクリア

5. std::variant

型安全な共用体:

#include <variant>

variant<int, double, string> v;

v = 42;
cout << get<int>(v) << endl;

v = "Hello";
cout << get<string>(v) << endl;

// 現在の型を確認
v.index();                         // 2
holds_alternative<string>(v);      // true

// visitor
visit([](auto&& arg) {
    cout << arg << endl;
}, v);

6. std::any

任意の型を保持:

#include <any>

any a = 42;
cout << any_cast<int>(a) << endl;

a = string("Hello");
cout << any_cast<string>(a) << endl;

// 型チェック
a.has_value();
a.type().name();

// 間違った型でキャストすると例外
try {
    any_cast<int>(a);  // bad_any_cast
} catch (const bad_any_cast& e) { }

7. std::string_view

文字列の軽量な参照:

#include <string_view>

void print(string_view sv) {
    cout << sv << endl;
}

print("literal");      // コピーなし
print(some_string);    // コピーなし

// 部分文字列
string_view sv = "Hello World";
sv.substr(0, 5);       // "Hello"(コピーなし)
sv.remove_prefix(6);   // "World"

利点:

  • メモリ割り当てなし
  • const char*stringの両方を受け取れる

8. 折り畳み式

可変長テンプレートの処理を簡潔に:

// 右畳み込み
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

// 左畳み込み
template<typename... Args>
void print_all(Args... args) {
    ((cout << args << " "), ...);
}

sum(1, 2, 3, 4, 5);       // 15
print_all("a", "b", "c"); // a b c

9. インライン変数

ヘッダーで変数を定義:

// header.h
struct Config {
    inline static const string version = "1.0.0";
    inline static int counter = 0;
};

ODR(One Definition Rule)違反を防げる。

10. constexpr lambda

ラムダ式をコンパイル時に評価:

constexpr auto square = [](int n) constexpr {
    return n * n;
};

constexpr int result = square(5);  // 25

// 配列サイズに使用可能
int arr[square(3)];  // int arr[9]

11. ネストした名前空間

// C++14以前
namespace A { namespace B { namespace C {
    void func();
}}}

// C++17
namespace A::B::C {
    void func();
}

12. 属性

// [[nodiscard]] - 戻り値を無視すると警告
[[nodiscard]] int compute();

// [[maybe_unused]] - 未使用の警告を抑制
[[maybe_unused]] int x = 42;

// [[fallthrough]] - 意図的なフォールスルー
switch (x) {
    case 1:
        do_something();
        [[fallthrough]];
    case 2:
        do_more();
        break;
}

13. std::filesystem

ファイルシステム操作:

#include <filesystem>
namespace fs = filesystem;

fs::path p = fs::current_path();
fs::path file = p / "test.txt";

// パス操作
file.filename();     // "test.txt"
file.extension();    // ".txt"
file.parent_path();  // 親ディレクトリ

// ファイル操作
fs::exists(file);
fs::is_directory(p);
fs::file_size(file);
fs::remove(file);
fs::copy(src, dst);

14. std::clamp

値を範囲内に制限:

clamp(10, 0, 100);   // 10
clamp(-5, 0, 100);   // 0
clamp(150, 0, 100);  // 100

15. map の新メソッド

map<string, int> m;

// try_emplace: キーが存在しなければ追加
m.try_emplace("key", 1);     // 追加
m.try_emplace("key", 100);   // 既存なので無視

// insert_or_assign: 存在すれば更新
m.insert_or_assign("key", 100);  // 更新

まとめ

機能 説明
構造化束縛 auto [a, b] = pair
if constexpr コンパイル時分岐
if初期化 if (auto x = ...; cond)
optional 値があるかもしれない型
variant 型安全な共用体
any 任意の型
string_view 軽量な文字列参照
折り畳み式 (args + ...)
inline変数 ヘッダーでの変数定義
filesystem ファイル操作
5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?