Reputation: 832
I am trying to visit a variant containing several classes. One of them does not have a specific field value
but I handle it with constexpr
, however, the compiler still fails to compile.
#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:
error: ‘const struct A’ has no member named ‘value’
22 | return data.value;
Compiler version:
clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Do I miss something or it is impossible by design?
EDIT:
The shortest solution was to use std::decay_t
, however, I don't know if there can be any consequences:
if constexpr (std::is_same_v<std::decay_t<decltype(data)>, A>)
Upvotes: 2
Views: 129
Reputation: 11271
Alternatively, you could use the overloaded
helper, as suggested by cppref.
#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;
}
Upvotes: 1
Reputation: 42756
You need remove reference and cv-qualifiers of the 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);
In C++20, you can just use the requires
clause to detect whether the data.value
expression is valid.
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);
Upvotes: 4