Consider this snippet:
#include <stdexcept>
template <typename T> class MyClass;
template <typename T> struct MyClass<T &> {
constexpr T &foo() && {
return value != nullptr ? std::move(*value)
: throw std::runtime_error("foo");
}
constexpr decltype(auto) bar() && {
return value != nullptr ? std::move(*value)
: throw std::runtime_error("bar");
}
T *value;
};
int main() {
const int &good = MyClass<int &>{}.bar();
const int &bad = MyClass<int &>{}.foo();
}
Why is return specification decltype(auto)
in method bar
working, while T&
in foo
does not?
CodePudding user response:
Why decltype(auto) infers T& as return type
No, the return type of bar()
is T&&
, i.e. int&&
in this case. For decltype
:
if the value category of expression is xvalue, then decltype yields T&&;
std::move(*value)
is an xvalue-expression, so the deduced return type is T&&
.
On the other hand, the return type of foo
is specified as T&
, but std::move(*value)
is an xvalue (rvalue) and can't be bound to T&
, i.e. an lvalue-reference to non-const.