std::visit
| ヘッダ <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) 型のパック) とします:
v を次のように呼び出します:
INVOKE(std::forward<Visitor>(v),std::get<indices>(std::forward<VariantBases>(values))...),
ここで indices は as-variant(values).index()... です。
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
as-variant 関数テンプレートは、推論可能な型の値を受け入れます (std::variant<Ts...> について、すなわち std::variant<Ts...> または std::variant<Ts...> から派生した型)。そして、同じ const 修飾と値カテゴリを持つ std::variant の値を返します。value を返します。std::move(value) を返します。パラメータ
| v | - | Callable であり、 Variants 内のすべてのvariantから取り得るすべての選択肢を受け入れるもの |
| values | - | ビジタに渡すvariantのリスト |
戻り値
例外
例外を送出
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
と交換する
(公開メンバ関数) |