-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathstd_visit.cpp
More file actions
171 lines (147 loc) · 5.28 KB
/
std_visit.cpp
File metadata and controls
171 lines (147 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Companion to docs/any_variant_optional.md §3 — std::variant.
//
// Covers the doc's full progression:
// - holds_alternative / get / get_if
// - the minimal generic-lambda visit
// - hand-written visitor struct (Step A in the doc)
// - overloaded{Fs...} helper (Step B)
// - returning a value from visit
// - multi-variant visit (cross-product dispatch)
// - PlanResult: the canonical planner example with three outcomes
#include <iostream>
#include <string>
#include <variant>
#include <vector>
// --- The overloaded helper (doc Step B, would normally live in a util header) ---
template <class... Fs> struct overloaded : Fs... {
using Fs::operator()...;
};
template <class... Fs> overloaded(Fs...) -> overloaded<Fs...>;
// --- Planner result: three outcomes, each with its own data ---
struct Pose {
double x, y;
};
struct PathFound {
std::vector<Pose> waypoints;
double cost;
};
struct NoPath {
std::string reason;
};
struct Partial {
std::vector<Pose> waypoints;
double coverage;
};
using PlanResult = std::variant<PathFound, NoPath, Partial>;
// --- Sensor message bus (doc's other canonical example) ---
struct LidarScan {
std::vector<float> ranges;
};
struct ImuSample {
float ax, ay, az;
};
struct GpsFix {
double lat, lon;
};
using SensorMsg = std::variant<LidarScan, ImuSample, GpsFix>;
// Step A: hand-written visitor struct (one operator() per alternative).
// Forget one alternative and this won't compile.
struct SensorVisitor {
void operator()(const LidarScan &s) const {
std::cout << " LidarScan: " << s.ranges.size() << " ranges\n";
}
void operator()(const ImuSample &s) const {
std::cout << " ImuSample: a=(" << s.ax << "," << s.ay << "," << s.az << ")\n";
}
void operator()(const GpsFix &s) const {
std::cout << " GpsFix: " << s.lat << ", " << s.lon << '\n';
}
};
void demo_get_and_get_if() {
std::cout << "--- holds_alternative / get / get_if ---\n";
PlanResult r = PathFound{{{0, 0}, {1, 1}, {2, 2}}, /*cost=*/12.4};
std::cout << " active index: " << r.index() << " (0=PathFound, 1=NoPath, 2=Partial)\n";
if (std::holds_alternative<PathFound>(r)) {
const auto &p = std::get<PathFound>(r);
std::cout << " PathFound: " << p.waypoints.size() << " waypoints, cost=" << p.cost << '\n';
}
// get_if returns nullptr instead of throwing — preferred for "maybe this type."
r = NoPath{"goal in obstacle"};
if (auto *p = std::get_if<NoPath>(&r))
std::cout << " NoPath: " << p->reason << '\n';
if (auto *p = std::get_if<PathFound>(&r))
std::cout << " PathFound (won't print): " << p->cost << '\n';
}
void demo_minimal_visit() {
std::cout << "--- minimal visit with one generic lambda ---\n";
std::variant<int, double, std::string> v = 3.14;
std::visit([](const auto &x) { std::cout << " " << x << '\n'; }, v);
v = std::string{"hi"};
std::visit([](const auto &x) { std::cout << " " << x << '\n'; }, v);
}
void demo_visitor_struct() {
std::cout << "--- Step A: hand-written visitor struct ---\n";
std::vector<SensorMsg> bus = {
LidarScan{{1.0f, 2.0f, 3.0f}},
ImuSample{0.1f, 0.0f, 9.81f},
GpsFix{37.7749, -122.4194},
};
for (const auto &m : bus)
std::visit(SensorVisitor{}, m);
}
void demo_overloaded() {
std::cout << "--- Step B: overloaded{...} helper, inline ---\n";
PlanResult outcomes[] = {
PathFound{{{0, 0}, {1, 0}}, 7.0},
NoPath{"unreachable"},
Partial{{{0, 0}}, 0.42},
};
// The PlanResult dispatcher the doc walks through — each branch handles only
// the data that actually makes sense for that outcome. Add a fourth
// alternative to PlanResult and this won't compile until a handler is added.
for (const auto &r : outcomes) {
std::visit(overloaded{
[](const PathFound &p) {
std::cout << " PathFound: " << p.waypoints.size()
<< " waypoints, cost=" << p.cost << '\n';
},
[](const NoPath &n) {
std::cout << " NoPath: " << n.reason << '\n';
},
[](const Partial &p) {
std::cout << " Partial: coverage=" << p.coverage << '\n';
},
},
r);
}
}
void demo_return_value() {
std::cout << "--- returning a value from visit ---\n";
auto estimateLatencyMs = [](const SensorMsg &m) {
return std::visit(overloaded{
[](const LidarScan &) { return 30.0; },
[](const ImuSample &) { return 1.0; },
[](const GpsFix &) { return 50.0; },
},
m);
};
SensorMsg msgs[] = {LidarScan{}, ImuSample{}, GpsFix{}};
for (const auto &m : msgs)
std::cout << " latency = " << estimateLatencyMs(m) << " ms\n";
}
void demo_multi_visit() {
std::cout << "--- multi-variant visit (cross-product dispatch) ---\n";
std::variant<int, double> a = 1;
std::variant<int, double> b = 2.0;
// visit passes one argument per variant to the callable.
auto sum = std::visit([](auto x, auto y) -> double { return x + y; }, a, b);
std::cout << " sum = " << sum << " (expected 3)\n";
}
int main() {
demo_get_and_get_if();
demo_minimal_visit();
demo_visitor_struct();
demo_overloaded();
demo_return_value();
demo_multi_visit();
}