【C++】any(std::any)で出来ることと使い方【標準ライブラリ】
std::anyとは?
std::any
は C++17 で導入された型安全な任意型のコンテナで、どんな型の値でも格納できるクラスです。
これまでC++で動的な型を扱うには、void*
や boost::any
を使用する方法が一般的でしたが、型安全性や使いやすさの面で問題がありました。C++17 では std::any
を使用することで、安全かつ直感的に任意の型の値を格納できます。
基本的な使い方
以下のコードは std::any
の基本的な使い方を示しています。
#include <iostream>
#include <any>
int main() {
std::any a = 42; // int 型の値を格納
std::cout << std::any_cast(a) << std::endl; // 42 を出力
a = std::string("Hello, std::any!"); // std::string 型の値に変更
std::cout << std::any_cast(a) << std::endl; // Hello, std::any! を出力
}
型安全とany_cast
std::any_cast<T>(a)
を使用して、格納された値を取得できます。ただし、型が一致しない場合は例外 std::bad_any_cast
が発生します。
#include <iostream>
#include <any>
int main() {
std::any a = 3.14;
try {
std::cout << std::any_cast(a) << std::endl; // 型が異なるので例外発生
} catch (const std::bad_any_cast& e) {
std::cout << "例外発生: " << e.what() << std::endl;
}
}
型を正しく扱うためには、事前に std::any_cast
を試す方法もあります。
#include <iostream>
#include <any>
int main() {
std::any a = 100;
if (a.type() == typeid(int)) {
std::cout << "int型: " << std::any_cast(a) << std::endl;
}
}
値の変更とリセット
std::any
の値を変更する場合は、新しい値を代入するだけです。また、reset()
を使うと値をクリアできます。
#include <iostream>
#include <any>
int main() {
std::any a = 42;
a = 3.14; // double型に変更
std::cout << std::any_cast(a) << std::endl;
a.reset(); // 値をリセット
if (!a.has_value()) {
std::cout << "値は空です" << std::endl;
}
}
型情報の取得
type()
メンバ関数を使うと、格納されている型の情報を取得できます。
#include <iostream>
#include <any>
#include <typeinfo>
int main() {
std::any a = 42;
std::cout << "型: " << a.type().name() << std::endl;
}
応用的な使用例
以下の例では、std::any
を std::vector
に格納して異なる型のデータを扱います。
#include <iostream>
#include <any>
#include <vector>
int main() {
std::vector data = { 42, 3.14, std::string("C++17") };
for (const auto& item : data) {
if (item.type() == typeid(int)) {
std::cout << "int: " << std::any_cast(item) << std::endl;
} else if (item.type() == typeid(double)) {
std::cout << "double: " << std::any_cast(item) << std::endl;
} else if (item.type() == typeid(std::string)) {
std::cout << "string: " << std::any_cast(item) << std::endl;
}
}
}
パフォーマンスと注意点
std::any
は汎用性が高いですが、使用時には以下の点に注意が必要です。
- 型情報のオーバーヘッド:
std::any
は型情報を内部に保持するため、メモリ使用量が増加する可能性があります。 - 動的メモリ確保: 大きなデータ型を格納する場合、内部でヒープ確保が行われる可能性があります。
- アクセスコスト:
std::any_cast
を使う際、型のチェックが発生するため、直接型を指定した変数を使うよりも遅くなります。
そのため、頻繁なアクセスが必要な場合は std::variant
や通常の型を使用することも検討すると良いでしょう。