das*_*fex 19 c++ c++17 std-variant
我有一些var = std::variant<std::monostate, a, b, c>什么时候a, b, c是一些类型。
如何在运行时检查var包含什么类型?
在官方文档中,我发现如果var包含a类型并且我写的信息,std::get<b>(var)我会得到一个异常。所以我想到了这个解决方案:
try {
std::variant<a>(var);
// Do something
} catch(const std::bad_variant_access&) {
try {
std::variant<b>(var);
// Do something else
} catch(const std::bad_variant_access&) {
try {
std::variant<c>(var);
// Another else
} catch (const std::bad_variant_access&) {
// std::monostate
}
}
}
Run Code Online (Sandbox Code Playgroud)
但它是如此复杂和丑陋!有没有更简单的方法来检查std::variant包含什么类型?
Jar*_*d42 15
std::visit 是要走的路:
甚至overloaded允许内联访问者:
// 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...>;
`overloaded`
Run Code Online (Sandbox Code Playgroud)
所以:
std::visit(overloaded{
[](std::monostate&){/*..*/},
[](a&){/*..*/},
[](b&){/*..*/},
[](c&){/*..*/}
}, var);
Run Code Online (Sandbox Code Playgroud)
要改用链接的 if 分支,您可能会使用 std::get_if
if (auto* v = std::get_if<a>(var)) {
// ...
} else if (auto* v = std::get_if<b>(var)) {
// ...
} else if (auto* v = std::get_if<c>(var)) {
// ...
} else { // std::monostate
// ...
}
Run Code Online (Sandbox Code Playgroud)
Jan*_*tke 13
最简单的方法是switch基于当前 std::variant::index(). 这种方法要求您的类型 ( std::monostate, A, B, C) 始终保持相同的顺序。
// I omitted C to keep the example simpler, the principle is the same
using my_variant = std::variant<std::monostate, A, B>;
void foo(my_variant &v) {
switch (v.index()) {
case 0: break; // do nothing because the type is std::monostate
case 1: {
doSomethingWith(std::get<A>(v));
break;
}
case 2: {
doSomethingElseWith(std::get<B>(v));
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您的可调用对象适用于任何类型,您还可以使用std::visit:
void bar(my_variant &v) {
std::visit([](auto &&arg) -> void {
// Here, arg is std::monostate, A or B
// This lambda needs to compile with all three options.
// The lambda returns void because we don't modify the variant, so
// we could also use const& arg.
}, v);
}
Run Code Online (Sandbox Code Playgroud)
如果您不想std::visit接受std::monostate,则只需检查 是否index为 0。再一次,这依赖于std::monostate变体的第一种类型,因此始终将其设为第一种是一种很好的做法。
您还可以使用if-constexpr内部调用检测类型。使用这种方法,参数不必再按相同顺序排列:
void bar(my_variant &v) {
std::visit([](auto &&arg) -> my_variant {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<std::monostate, T>) {
return arg; // arg is std::monostate here
}
else if constexpr (std::is_same_v<A, T>) {
return arg + arg; // arg is A here
}
else if constexpr (std::is_same_v<B, T>) {
return arg * arg; // arg is B here
}
}, v);
}
Run Code Online (Sandbox Code Playgroud)
请注意,第一个 lambda 返回,void因为它只处理变体的当前值。如果您想修改变体,您的 lambda 需要my_variant再次返回。
您可以在内部使用重载访问者std::visit来处理A或B单独处理。有关std::visit更多示例,请参见。
| 归档时间: |
|
| 查看次数: |
2863 次 |
| 最近记录: |