如果其中一个备选方案没有特定字段,则无法访问该变体
Unable to visit a variant if one of its alternatives does not have a specific field
我正在尝试访问包含多个 类 的变体。其中一个没有指定字段value
,我用constexpr
处理了,但是编译器还是编译不通过。
#include <variant>
#include <iostream>
struct A {};
struct B {
int value = 1;
};
struct C {
int value = 2;
};
int main() {
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(
[&](auto &data) -> int {
if constexpr (std::is_same_v<decltype(data), A>) {
return int{0};
} else {
return data.value;
}
},
d);
std::cout << n << std::endl;
return 0;
}
错误:
error: ‘const struct A’ has no member named ‘value’
22 | return data.value;
编译器版本:
clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
我是不是漏掉了什么或者设计上是不可能的?
编辑:
最短的解决方案是使用std::decay_t
,但是,我不知道是否会有任何后果:
if constexpr (std::is_same_v<std::decay_t<decltype(data)>, A>)
您需要删除 data
:
的引用和 cv-qualifiers
auto n = std::visit(
[&](auto &data) -> int {
if constexpr (std::is_same_v<std::remove_cvref_t<decltype(data)>, A>) {
return int{0};
} else {
return data.value;
}
},
d);
在C++20中,你可以只使用requires
子句来检测data.value
表达式是否有效。
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(
[&](auto& data) -> int {
if constexpr (requires { data.value; }) {
return data.value;
} else {
return int{0};
}
},
d);
或者,您可以按照 cppref 的建议使用 overloaded
助手。
#include <variant>
#include <iostream>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
struct A {};
struct B {
int value = 1;
};
struct C {
int value = 2;
};
int main() {
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(overloaded{
[](auto const& data){return data.value;},
[](A const&){return 0;}
}, d);
std::cout << n << '\n';
return 0;
}
我正在尝试访问包含多个 类 的变体。其中一个没有指定字段value
,我用constexpr
处理了,但是编译器还是编译不通过。
#include <variant>
#include <iostream>
struct A {};
struct B {
int value = 1;
};
struct C {
int value = 2;
};
int main() {
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(
[&](auto &data) -> int {
if constexpr (std::is_same_v<decltype(data), A>) {
return int{0};
} else {
return data.value;
}
},
d);
std::cout << n << std::endl;
return 0;
}
错误:
error: ‘const struct A’ has no member named ‘value’
22 | return data.value;
编译器版本:
clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
我是不是漏掉了什么或者设计上是不可能的?
编辑:
最短的解决方案是使用std::decay_t
,但是,我不知道是否会有任何后果:
if constexpr (std::is_same_v<std::decay_t<decltype(data)>, A>)
您需要删除 data
:
auto n = std::visit(
[&](auto &data) -> int {
if constexpr (std::is_same_v<std::remove_cvref_t<decltype(data)>, A>) {
return int{0};
} else {
return data.value;
}
},
d);
在C++20中,你可以只使用requires
子句来检测data.value
表达式是否有效。
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(
[&](auto& data) -> int {
if constexpr (requires { data.value; }) {
return data.value;
} else {
return int{0};
}
},
d);
或者,您可以按照 cppref 的建议使用 overloaded
助手。
#include <variant>
#include <iostream>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
struct A {};
struct B {
int value = 1;
};
struct C {
int value = 2;
};
int main() {
const auto d = std::variant<A, B, C>{B{}};
auto n = std::visit(overloaded{
[](auto const& data){return data.value;},
[](A const&){return 0;}
}, d);
std::cout << n << '\n';
return 0;
}