【C++17】std::any の使い方 | あらゆる型の値を安全に保持する方法

目次

はじめに

C++は静的型付け言語であり、通常、一つの変数には一つの決まった型の値しか格納できません。しかし、時には「コンテナにintstringも、自作クラスも、何でもかんでも格納したい」という場面があります。

C++17より前は、このような要求には void* や共用体 (union) が使われていましたが、型安全性が低く、危険なキャストが必要でした。

この問題を解決するのが std::any です。std::any は、あらゆる型の値を安全に保持できる型で、中身を取り出す際には、std::any_cast を使って、厳密な型チェックの元で安全に値を取り出すことができます。


【前提】C++17とは?

C++17(シーピープラスいちなな)は、2017年に正式化されたC++言語の規格です。std::any はこのC++17で追加された機能のため、利用するにはC++17に対応したコンパイラが必要です。


std::any を使ったサンプルコード

このコードは、std::any 型の変数 data に、int, double, std::string と、次々に異なる型の値を代入し、その都度 any_cast を使って値を取り出す様子を示します。

完成コード

#include <iostream>
#include <any>      // std::any, std::any_cast
#include <string>
#include <typeinfo> // typeid

using namespace std;

int main() {
    // 1. std::any 変数を宣言
    any data;
    
    // --- int値を代入 ---
    data = 100;
    // .type()で、現在保持している型を調べる
    if (data.type() == typeid(int)) {
        // 2. any_cast<T>で、指定した型Tとして値を取り出す
        int n = any_cast<int>(data);
        cout << "int値: " << n << endl;
    }
    
    // --- string値を代入 ---
    data = string("こんにちは");
    if (data.type() == typeid(string)) {
        string s = any_cast<string>(data);
        cout << "string値: " << s << endl;
    }

    // --- 不正なキャストを試みる ---
    try {
        // 現在はstringが入っているので、doubleへのキャストは失敗し、例外を投げる
        double d = any_cast<double>(data);
    }
    catch (const bad_any_cast& e) {
        cout << "エラー: " << e.what() << endl;
    }
    
    // --- 3. ポインタを使った安全なキャスト ---
    // もしdataの中身がstring*でなければ、p_strはnullptrになる
    if (string* p_str = any_cast<string>(&data)) {
        cout << "ポインタ経由での値: " << *p_str << endl;
        // ポインタ経由で元の値を変更
        *p_str = "さようなら";
    }
    
    // 元の値が変わっていることを確認
    cout << "変更後のstring値: " << any_cast<string>(data) << endl;

    return 0;
}

コードの解説

1. any data; と代入

std::any 型の変数を宣言します。この data 変数には、int, double, string や自作クラスなど、コピー可能なあらゆる型の値を代入できます。代入すると、data はその値のコピーを内部に保持します。

2. any_cast<T>(data)

any に格納された値を取り出すには、std::any_cast を使います。

  • any_cast<int>(data): <>の中に、取り出したい型を指定します。
  • 型チェック: any_cast は、any が現在保持している型と、指定された型が完全に一致するかをチェックします。
    • 一致する場合: その型の値を返します。
    • 一致しない場合: std::bad_any_cast という例外を投げます。これにより、不正な型変換によるプログラムのクラッシュを防ぎます。

3. any_cast<string>(&data)

any_cast の引数に any オブジェクトへのポインタを渡すと、挙動が変わります。

  • 戻り値: 指定した型へのポインタを返します。
  • キャスト失敗時: 例外を投げる代わりに、nullptr を返します。

if 文と組み合わせることで、try-catch ブロックなしで、より簡潔に安全なキャストを行うことができます。


まとめ

今回は、C++17で導入された std::any を使って、型安全な方法であらゆる値を保持する方法を解説しました。

  • std::any: あらゆる型の値を保持できるラッパー。
  • any.type() == typeid(T): 現在の型を調べることができる。
  • std::any_cast<T>(any): 型をチェックしながら、安全に値を取り出す。キャストに失敗すると例外を投げる。
  • std::any_cast<T*>(&any): ポインタとして安全に値を取り出す。キャストに失敗すると nullptr を返す。

std::any は、異なる型のデータを一つのコレクションに格納したい場合など、静的な型システムの制約を安全に乗り越えるための強力なツールです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次