You can say this instead:
1 2
|
template<class T>
decltype(auto) foo(T& d, int i) { return d[i]; }
|
auto and
decltype(auto) are called
placeholder types. Those types are deduced in a process called
placeholder type deduction.
If
auto is used as a placeholder type, the type is deduced using the rules about template argument deduction. If
decltype(auto) is used, the rules about
decltype are used instead.
In certain circumstances,
decltype returns a reference type if the expression it is applied to has the correct value category. Our case is one such circumstance*.
In our case, the return type of
foo<std::vector<int>> is an lvalue reference type, because placeholder type deduction applies
decltype to
d[i] where
d is a
std::vector<int>. This is an lvalue expression, so
decltype(auto) is deduced as
std::vector<int>::value_type &.
In contrast, the return type of
foo<std::vector<bool>> is a value type, because placeholder type deduction applies
decltype to
d[i] where
d is a
std::vector<bool>. This is a prvalue expression, so
decltype(auto) is deduced as
std::vector<bool>::reference.
The result is that our function works fine in both cases.
1. This circumstance is deduction from an expression that is not an unparenthesized id-expression (name) or unparenthesized member-access expression. See:
https://en.cppreference.com/w/cpp/language/decltype
https://timsong-cpp.github.io/cppwp/n4659/dcl.type.simple#4