I have the following test code.
See godbolt https://godbolt.org/z/fLRM8d for an executable example
template <typename T> struct Traits {
static const bool value = false;
};
struct Zip{};
template <> struct Traits<Zip> {
static const bool value = true;
};
template <typename E>
void Execute(E && e){
static_assert(Traits<E>::value);
}
int main(){
auto z = Zip();
// Fails the static assertion with an lvalue
Execute(z);
// Passes the static assertion with an rvalue
Execute(Zip());
}
What is going on here that I can't use my type trait as I expect? What is the correct way to model this problem?
There is a special rule regarding deduction of forwarding references in the Standard. Given a forwarding reference parameter T&&
, T
will be deduced as an lvalue reference if the function is called with an lvalue.
You need to take this into account in your traits:
Traits<std::remove_reference_t<E>>::value
live example on godbolt.org
From the Standard:
http://eel.is/c++draft/temp.deduct.call#3
A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With