This is basically just going to be the ‘Things to Remember’ from the chapter.
During template type deduction, arguments that are references are deduced as non-references (although the arguments themselves retain their reference-ness).
template <typename T> void f (T& arg) {}
auto x = int { 0 }; f (x); // T is int
const auto cx = x; f (cx); // T is const int
const auto& rx = x; f (rx); // T is const int
Forwarding references treat lvalue references specially. For lvalue references, T and the parameter itself retain their ref-ness. For rvalues, the normal rules apply, so T’s ref-ness is removed.
template <typename T> void f (T&& arg) {}
auto x = int { 0 }; f (x); // T is int&
const auto cx = x; f (cx); // T is const int&
const auto& rx = x; f (rx); // T is const int&
f (0); // T is int
By-value parameters will have their ref-ness, const-ness and volatile-ness removed.
template <typename T> void f (T arg) {}
Arrays and function arguments decay to pointers, unless they’re used to initialise references.
Auto type deduction is the same as template type deduction, with the exception of std::initialiser_list. If you’re going to use brace initialisation with auto, it’s important to put the type on the rhs!
auto x = { 0 }; // initializer_list, oh no!
auto parameters or return types use the template rules. They won’t deduce an initialiser_list type in those cases.
Decltype yields the type of a variable or expression. There’s a gotcha where wrapping a variable in parens means it’s no longer a name expression, which might affect its ref-ness.
int x = 0;
decltype ((x)) // int&
decltype(auto)
will apply the decltype deduction rules when deducing the type. That is, it will
retain the constenss and ref-ness of returned values. Be careful not to return lvalue references to
temporaries when using decltype(auto)
.
return (some_expression)
Deduced types can be viewed by forcing a template instantiation error involving the type in question, or by using an IDE (support seems questionable though) or boost TypeIndex.
template <typename T> struct Error;
Error<decltype(some_expression)> e;
Is a knowledge of prvalues, xvalues, glvalues, rvalues etc. useful? I know they exist, but I don’t really know the definitions, and I’m not sure whether I should.
Is it helpful to specifically say auto*
when initialising a variable with the result of a function
which returns a pointer? If I was writing a template function which expected to only operate on
pointers, I probably wouldn’t put a pointer in the parameter list, but maybe that’s a mistake.