Namespaces
Variants

std::visit

ja.cppreference.net より
 
 
ユーティリティライブラリ
言語サポート
型サポート (基本型、RTTI)
ライブラリ機能テストマクロ (C++20)
プログラムユーティリティ
可変引数関数
コルーチンサポート (C++20)
契約サポート (C++26)
三方比較
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

汎用ユーティリティ
関係演算子 (C++20で非推奨)
整数比較関数
(C++20)(C++20)(C++20)    
(C++20)
Swap および 型操作
(C++14)
(C++11)
(C++11)
(C++11)
(C++17)
共通語彙型
(C++11)
(C++17)
(C++17)
(C++17)
(C++11)
(C++17)
(C++23)



 
 
ヘッダ <variant>
template< class Visitor, class... Variants >
constexpr /* see below */ visit( Visitor&& v, Variants&&... values );
で定義 (1) (C++17以降)
template< class R, class Visitor, class... Variants >
constexpr R visit( Visitor&& v, Variants&&... values );
(2) (C++20以降)
ヘルパーテンプレート
template< class... Ts >
auto&& as-variant( std::variant<Ts...>& value );
(3) (説明専用*)
template< class... Ts >
auto&& as-variant( const std::variant<Ts...>& value );
(4) (説明専用*)
template< class... Ts >
auto&& as-variant( std::variant<Ts...>&& value );
(5) (説明専用*)
template< class... Ts >
auto&& as-variant( const std::variant<Ts...>&& value );
(6) (説明専用*)

ビジター v (Variant の任意の型の組み合わせで呼び出し可能な Callable) を Variants values に適用します。

ここで、VariantBases を decltype(as-variant(std::forward<Variants>(values))... (sizeof...(Variants) 型のパック) とします:

1) v を次のように呼び出します:

INVOKE(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...)
, ここで indices は as-variant(values).index()... です。

2) v を次のように呼び出します:

INVOKE<R>(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...)
, ここで indices は as-variant(values).index()... です。

これらのオーバーロードは、VariantBases のすべての型が有効な型である場合にのみオーバーロード解決に参加します。INVOKE または INVOKE<R>(C++20以降) で示される式が無効であるか、異なる INVOKE または INVOKE<R>(C++20以降) の結果が異なる型または値カテゴリを持つ場合、プログラムは不適格となります。 indices

3-6) 説明専用の as-variant 関数テンプレートは、推論可能な型の値を受け入れます (std::variant<Ts...> について、すなわち std::variant<Ts...> または std::variant<Ts...> から派生した型)。そして、同じ const 修飾と値カテゴリを持つ std::variant の値を返します。
3,4) value を返します。
5,6) std::move(value) を返します。

パラメータ

v - Callable であり、 Variants 内のすべてのvariantから取り得るすべての選択肢を受け入れるもの
values - ビジタに渡すvariantのリスト

戻り値

1) INVOKE 操作の結果。戻り値の型は、結果に decltype を適用して得られる型です。
2) R が(CV修飾されている可能性のある) void の場合は何も返さない。それ以外の場合は INVOKE<R> 操作の結果を返す。
3-6) std::variant から変換された value 値。

例外

例外を送出 std::bad_variant_access 条件: as-variant ( value_i ) . valueless_by_exception ( ) が true の場合( values 内の任意のvariant value_i に対して)。

計算量

バリアントの数が0または1の場合、呼び出し可能オブジェクトの呼び出しは定数時間で実装されます。つまり、バリアントに格納可能な型の数に依存しません。

バリアントの数が1より大きい場合、呼び出し可能オブジェクトの呼び出しには複雑性の要件はありません。

注記

n を ( 1 * ... * std:: variant_size_v < std:: remove_reference_t < VariantBases >> ) とすると、実装は通常、 std::visit のすべての特殊化に対して n 個の関数ポインタの(多次元の可能性がある)配列に相当するテーブルを生成します。これは virtual functions の実装と同様です。

実装はまた、 switch文 を n 個の分岐で std::visit に対して生成する場合もある(例えば、MSVC STL実装では n が256を超えない場合にswitch文を使用する)。

一般的な実装では、 v の呼び出しの時間計算量は、(多次元の可能性もある)配列の要素へのアクセスやswitch文の実行と同等と見なすことができます。

機能テスト マクロ 値 標準 機能
__cpp_lib_variant 202102L (C++23)
(DR17)
std::visit を std::variant から派生したクラスに対して使用

例

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// 訪問するバリアント
using value_t = std::variant<int, long, double, std::string>;
// ビジター #4 のためのヘルパー型
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// 明示的な推定ガイド (C++20以降では不要)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
    std::vector<value_t> vec = {10, 15l, 1.5, "hello"};
    for (auto& v: vec)
    {
        // 1. void visitor, 副作用のみを目的として呼び出される(ここではI/Oのため)
        std::visit([](auto&& arg){ std::cout << arg; }, v);
        // 2. 値を返すビジター、別のバリアントを返すイディオムを示す
        value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v);
        // 3. 型マッチングビジター: 各型を異なる方法で処理するラムダ
        std::cout << ". 倍増後、variantは保持する ";
        std::visit([]

(注:元のテキスト「]」はHTMLタグ内の閉じ括弧であり、翻訳対象外のためそのまま保持しました)(auto&& arg)
        {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "値を持つ int " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "値を持つ long" << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "値を持つ double " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "値を持つ std::string " << std::quoted

(注:指示に従い、HTMLタグ・属性は翻訳せず、C++固有用語も翻訳していません。表示されるテキスト「std::quoted」はC++標準ライブラリの関数名であるため、そのまま保持しています)(arg) << '\n';
            else
                static_assert(false, "網羅的でないビジター!");
        }, w);
    }
    for (auto& v: vec)
    {
        // 4. another type-matching visitor: a class with 3 overloaded operator()'s
        // 注: `(auto arg)` テンプレート operator() は `int` と `long` にバインドします
        //       このケースでは、しかしその不在においては `(double arg)` operator()
        //       *will also* bind to `int` and `long` because both are implicitly
        //       doubleに変換可能であること。この形式を使用する場合、注意が必要です
        //       暗黙の変換が正しく処理されること。
        std::visit(overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted

(注:指示に従い、HTMLタグ・属性は翻訳せず、C++固有の用語も翻訳していません。表示されるテキスト「std::quoted」はC++標準ライブラリの関数名であるため、そのまま保持しています)(arg) << ' '; }
        }, v);
    }
}

出力:

10. 倍増後、variantは値20のintを保持
15. 倍増後、variantは値30のlongを保持
1.5. 倍増後、variantは値3のdoubleを保持
hello. 倍増後、variantは値"hellohello"のstd::stringを保持
10 15 1.500000 "hello"

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
LWG 2970 C++17 オーバーロード (1) の戻り値型が
INVOKE 操作の結果の値カテゴリを
保持していなかった
保持する
LWG 3052
( P2162R2 )
C++17 Variants 内のいずれかの型が
std::variant でない場合の効果が
未規定だった
規定する

関連項目

(C++26)
保持されている引数で提供されたファンクタを呼び出す variant
(公開メンバ関数)
別の variant と交換する
(公開メンバ関数)