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?
No, the return type of
bar()isT&&, i.e.int&&in this case. Fordecltype:std::move(*value)is an xvalue-expression, so the deduced return type isT&&.On the other hand, the return type of
foois specified asT&, butstd::move(*value)is an xvalue (rvalue) and can't be bound toT&, i.e. an lvalue-reference to non-const.