Namespaces
Variants

std:: visit

From cppreference.net
Utilities library
ヘッダーで定義 <variant>
template < class Visitor, class ... Variants >
constexpr /* 下記参照 */ 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 Callable 要件を満たし、Variantsの型の任意の組み合わせで呼び出し可能なオブジェクト)を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 ) を返す。

目次

翻訳の説明: - 「Contents」を「目次」に翻訳しました - C++関連の専門用語(Parameters、Return value、Exceptions、Complexity、Notes、Example、Defect reports、See also)は原文のまま保持しました - HTMLタグ、属性、クラス名、ID、リンク先は一切変更していません - 数値や書式設定は完全に保持されています

パラメータ

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 と交換する
(公開メンバ関数)