std::visit
variantの選択肢を処理します
「std::visit」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
std::visitを使う理由
get_ifで各候補を手動で確認すると、コードが冗長になります。std::visitはvariantが現在保持している型の値に対して呼び出し可能オブジェクトを適用し、振り分けを自動的に処理します。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 4;
std::visit([](auto x){ std::cout << x << "\n"; }, v);
}ジェネリックラムダビジター
autoを受け取るラムダは、本体がすべての候補に対してコンパイルできれば、どの候補にも使えます。ここではアクティブな型の値を表示します。
#include <iostream>
#include <string>
#include <variant>
int main() {
std::variant<int, std::string> v = std::string("hi");
std::visit([](const auto& x){ std::cout << x << "\n"; }, v);
}値を返す
std::visitは値を返すこともできます。すべての分岐で同じ型を返す必要があります。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 2.5;
double d = std::visit([](auto x){ return x * 2.0; }, v);
std::cout << d << "\n";
}if constexprによる型ごとの処理
1つのジェネリックラムダの内部で型ごとに異なる処理を行うには、if constexprをstd::decay_tおよびstd::is_same_vと組み合わせます。
#include <iostream>
#include <string>
#include <variant>
#include <type_traits>
int main() {
std::variant<int, std::string> v = 5;
std::visit([](const auto& x){
using T = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<T, int>) std::cout << "int " << x << "\n";
else std::cout << "str " << x << "\n";
}, v);
}構造体ビジター
複数のoperator()オーバーロードを持つ構造体を、型ごとに1つずつ定義することもできます。コンパイラーが一致するオーバーロードを選択します。
#include <iostream>
#include <string>
#include <variant>
struct Printer {
void operator()(int i) const { std::cout << "int " << i << "\n"; }
void operator()(const std::string& s) const { std::cout << "str " << s << "\n"; }
};
int main() {
std::variant<int, std::string> v = std::string("yo");
std::visit(Printer{}, v);
}オーバーロードイディオム
複数のラムダを1つのビジターにまとめる、よく使われるヘルパーです。各ラムダが特定の型を処理します。
#include <iostream>
#include <string>
#include <variant>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::variant<int, std::string> v = 8;
std::visit(overloaded{
[](int i){ std::cout << "i=" << i << "\n"; },
[](const std::string& s){ std::cout << "s=" << s << "\n"; }
}, v);
}すべての候補への対応
ビジターはすべての候補を処理する必要があります。そうでなければ、コードはコンパイルに失敗します。このコンパイル時チェックにより、ケースの処理忘れを防げます。
訪問しながら変更する
variantをconstでない参照として渡すと、ビジターは格納されている値をその場で変更できます。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 10;
std::visit([](auto& x){ x += 1; }, v);
std::cout << std::get<int>(v) << "\n";
}複数のvariant
std::visitには複数のvariantを同時に渡せます。その場合、ビジターはvariantごとに1つの引数を受け取ります。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> a = 2;
std::variant<int, double> b = 3.0;
auto sum = std::visit([](auto x, auto y){ return x + y; }, a, b);
std::cout << sum << "\n";
}ビジタースタイルを選ぶ
一律に処理する場合はジェネリックなautoラムダを、型ごとに処理を分ける場合はオーバーロードイディオムを、複数の呼び出し箇所で動作を再利用する場合は構造体ビジターを使用してください。
visitとget_ifの比較
1回だけ簡単にチェックするならget_ifで十分ですが、規模が大きくなる場合はstd::visitが適しています。すべての候補への対応を強制し、型ごとの処理を1か所にまとめられます。
理解度チェック
std::visitについての理解を確認しましょう。
まとめ
std::visitについて、次のことを学びました:
- アクティブな候補に呼び出し可能オブジェクトを振り分けます。
- ジェネリックラムダ、
if constexpr、構造体ビジター、またはオーバーロードイディオムを使用します。 - ビジターはすべての候補に対応する必要があります(コンパイル時チェック)。
- 値を返すことができ、複数のvariantをまとめて処理できます。
よくある質問
「std::visit」レッスンは無料ですか?
はい。「std::visit」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「std::visit」で何を学びますか?
variantの選択肢を処理します ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「std::visit」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- スコープ付きenum class
- unionとそのリスク
- std::variant
- std::visit