読者です 読者をやめる 読者になる 読者になる

C++と色々

主にC++やプログラムに関する記事を投稿します。

std::variant

C++17にはstd::variantというライブラリが追加されます。 variantは組み込みのunionよりリッチなインターフェイスを持った型安全なunionです。*1 Visual Studio 2017にも入りましたので簡単なサンプルを書いてみました

#include <variant>
#include <iostream>
#include <string>

struct visitor
{
    void operator()(int) const
    {
        std::cout << "it's int" << std::endl;
    }

    void operator()(std::string const&) const
    {
        std::cout << "it's string" << std::endl;
    }
};

int main()
{
    std::variant<int, std::string> const vars[] = {3, "hello"};
    for (auto const& it : vars) {
        // visitでvariantの値にアクセスできる。値をファンクタに渡すことが出来ない場合はコンパイルエラーになる
        // (必要ならば)ファンクタはジェネリクスにするかオーバーロードしておく
        std::visit(visitor{}, it);
        // holds_alternativeはvariantにholds_alternativeのテンプレート引数に渡した型の値を持っていればtrueを返す
        // variantのテンプレート引数に存在しない型を指定するとコンパイルエラーになる
        std::cout << std::boolalpha << std::holds_alternative<int>(it) << std::endl;
        // std::getでvariantが保持している値の参照を取得する
        // テンプレート引数に渡した型の値を保持していない場合はstd::bad_variant_accessを投げる
        try {
            int value = std::get<int>(it);
            std::cout << "holding int value: " << value << std::endl;
        } catch (std::bad_variant_access const& e) {
            std::cout << e.what() << std::endl;
        }
        // std::get_ifでvariantが保持している値のポインタを取得する
        // テンプレート引数に渡した方のあたいを保持していない場合はnullptrを返す
        if (auto const value = std::get_if<int>(&it)) {
            std::cout << "holding int value: " << *value << std::endl;
        } else {
            std::cout << "not found" << std::endl;
        }
    }
}

実行結果

it's int
true
holding int value: 3
holding int value: 3
it's string
false
bad variant access
not found
Press any key to continue . . .

*1:代数データ型素人なので違っていたら優しく指摘してください…