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.
