std::visit
| ヘッダ <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) | (説明用*) |
Visitor (Variantsの型からのあらゆる組み合わせで呼び出し可能なCallable) v を、Variants の値 values に適用します。
VariantBases を decltype(as-variant(std::forward<Variants>(values))... ( sizeof...(Variants) 個の型のパック) として、
INVOKE(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...),
as-variant(values).index()... です。INVOKE<R>(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...),
as-variant(values).index()... です。これらのオーバーロードは、VariantBases のすべての型が有効な型である場合にのみ、オーバーロード解決に参加します。 INVOKE または INVOKE<R>(C++20以降) で示される式が無効である場合、または indices の型や値カテゴリが異なる場合、プログラムは不正形成となります。
as-variant 関数テンプレートは、std::variant<Ts...> のために型を推論できる値(つまり、std::variant<Ts...> または std::variant<Ts...> から派生した型)を受け取り、同じ const 修飾と値カテゴリを持つ std::variant 値を返します。目次 |
[編集] パラメータ
| v | - | Variants のすべてのバリアントのすべての可能な代替を受け入れる Callable |
| values | - | ビジターに渡すバリアントのリスト |
[編集] 戻り値
[編集] 例外
as-variant(value_i).valueless_by_exception() が、values 内の任意のバリアント value_i に対して true の場合、std::bad_variant_access をスローします。
[編集] 計算量
バリアントの数が 0 または 1 の場合、Callable オブジェクトの呼び出しは定数時間で実装されます。つまり、variant に格納できる型数に依存しません。
バリアントの数が 1 より大きい場合、Callable オブジェクトの呼び出しには計算量要件はありません。
[編集] 注記
n を (1 * ... * std::variant_size_v<std::remove_reference_t<VariantBases>>) とすると、実装では通常、std::visit のすべての特殊化に対して、(多次元の可能性もある) 関数ポインタの配列に相当するテーブルを生成します。これは 仮想関数 の実装に似ています。
実装では、std::visit のために n 個の分岐を持つ switch文 を生成する場合もあります (例: MSVC STL の実装では n が 256 以下の場合に switch文 を使用します)。
通常の И実装では、v の呼び出しの計算量は、(多次元の可能性もある) 配列の要素へのアクセスや switch文 の実行の計算量と同等と見なすことができます。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_variant |
202102L |
(C++23) (DR17) |
std::variant から派生したクラスに対する std::visit |
[編集] 例
#include <iomanip> #include <iostream> #include <string> #include <type_traits> #include <variant> #include <vector> // the variant to visit using value_t = std::variant<int, long, double, std::string>; // helper type for the visitor #4 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // explicit deduction guide (not needed as of 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, only called for side-effects (here, for I/O) std::visit([](auto&& arg){ std::cout << arg; }, v); // 2. value-returning visitor, demonstrates the idiom of returning another variant value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v); // 3. type-matching visitor: a lambda that handles each type differently std::cout << ". After doubling, variant holds "; std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, int>) std::cout << "int with value " << arg << '\n'; else if constexpr (std::is_same_v<T, long>) std::cout << "long with value " << arg << '\n'; else if constexpr (std::is_same_v<T, double>) std::cout << "double with value " << arg << '\n'; else if constexpr (std::is_same_v<T, std::string>) std::cout << "std::string with value " << std::quoted(arg) << '\n'; else static_assert(false, "non-exhaustive visitor!"); }, w); } for (auto& v: vec) { // 4. another type-matching visitor: a class with 3 overloaded operator()'s // Note: The `(auto arg)` template operator() will bind to `int` and `long` // in this case, but in its absence the `(double arg)` operator() // *will also* bind to `int` and `long` because both are implicitly // convertible to double. When using this form, care has to be taken // that implicit conversions are handled correctly. std::visit(overloaded{ [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; } }, v); } }
出力
10. After doubling, variant holds int with value 20 15. After doubling, variant holds long with value 30 1.5. After doubling, variant holds double with value 3 hello. After doubling, variant holds std::string with value "hellohello" 10 15 1.500000 "hello"
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 2970 | C++17 | オーバーロード (1) の返り値の型が、INVOKE 操作の結果の値カテゴリを保持していませんでした。 |
保持 |
| LWG 3052 (P2162R2) |
C++17 | Variants 内のいずれかの型が std::variant でない場合の動作が未指定でした。 |
指定された |
[編集] 関連項目
| (C++26) |
variant が保持する引数で、与えられたファンクタを呼び出す(public member function) |
別の variant と交換する(public member function) |