template<typename T>
constexpr auto log_value(T&& value) {
if constexpr (std::is_enum_v<T>) {
cout << "enum" << endl;
}
else {
cout << "normal" << endl;
}
}
I have a function to judge whether some value is an enum, and I test it by
enum class A {
a,
s,
d
};
int main() {
auto s = A::a;
const auto& s1 = s;
auto&& s2 = A::a;
log_value(s);
log_value(s1);
log_value(s2);
log_value(A::a);
But the result is
normal
normal
normal
enum
When I change it into:
template<typename T>
constexpr auto log_value_const_left(const T& value) {
if constexpr (std::is_enum_v<T>) {
cout << "enum" << endl;
}
else {
cout << "normal" << endl;
}
}
It works
enum
enum
enum
enum
Now I just wonder why log_value
doesn't work? Isn't the input parameter T&& value
in log_value
called universal reference which could refer to either lvalue reference or rvalue reference?
And if std::is_enum_v<T> != true
in log_value
,what is it exactly? Why it's changed anyway?
The way forwarding (aka universal) references work for lvalues is by deducing the referenced type (T
in your case) to an lvalue reference (A &
in your case). Then T &&
also becomes A &
according to the reference collapsing rules (&
+ &&
= &
).
For rvalues this is not needed, and T
is deduced to a non-reference.
You want std::is_enum_v<std::remove_reference_t<T>>
.