placeholder_type
About placeholder type: e.g. auto or decltype(auto)
Placeholder Type Specifiers in C++
1. Usage in Variable Declarations:
- Used in the type specifier sequence of a variable declaration (
auto x = expr). - Type is deduced from the initializer (
expr). autoordecltype(auto)deduces the variable type from the initializer.- If the placeholder type specifier is
autoor type-constraint auto(since C++20), the variable type is deduced from the initializer using the rules for template argument deduction from a function call For example, givenconst auto& i = expr;, the type ofiis exactly the type of the argumentuin an imaginary template, if the function callf(expr)was compiled.
template<class U> void f(const U& u)
2. Multiple Variable Declarations:
- If used to declare multiple variables, deduced types must match.
- Example:
auto i = 0, d = 0.0is ill-formed.
3. Usage in New Expressions:
- Appears in the type-id of a new expression.
- Type is deduced from the initializer (
Tis deduced as if forT x init).
4. Return Type of Functions/Lambdas:
- Can be used in the return type of a function or lambda expression.
- Return type is deduced from the operand of its non-discarded return statement.
5. Parameter Declaration of Non-type Template Parameters:
- Appears in the parameter declaration of a non-type template parameter.
- Type is deduced from the corresponding argument.
decltype(auto) is often considered as "perfect (forwarded) return type"
decltype(auto)provides a convenient way to deduce return types from expressions, preserving reference semantics and supporting generic programming scenarios.
C++ Weekly - Ep 344 - decltype(auto): An Overview of How, Why and Where
#include <type_traits>
int global_i = 42;
const int& fnc_return_const_ref() { return global_i; };
decltype(auto) showcase_perfect_return() {
return fnc_return_const_ref();
}
auto showcase_NOT_perfect_return() {
// as return is auto here, it does a template parameter
// deduction on the expression, then as the return type
return fnc_return_const_ref();
}
int main() {
// auto is like template parameter deduction for compiler
auto auto_i = fnc_return_const_ref();
static_assert(std::is_same_v<decltype(auto_i), int>);
auto& auto_ref_i = fnc_return_const_ref();
static_assert(std::is_same_v<decltype(auto_ref_i), const int&>);
const auto const_auto_i = fnc_return_const_ref();
static_assert(std::is_same_v<decltype(const_auto_i), const int>);
const auto& const_auto_ref_i = fnc_return_const_ref();
static_assert(std::is_same_v<decltype(const_auto_ref_i), const int&>);
// decltype(auto) deduces the exact type of an expression!
decltype(auto) decltype_auto_i = fnc_return_const_ref();
static_assert(std::is_same_v<decltype(decltype_auto_i), const int&>);
decltype(auto) perfect_return_show_i = showcase_perfect_return();
static_assert(std::is_same_v<decltype(perfect_return_show_i), const int&>);
decltype(auto) not_perfect_return_show_i = showcase_NOT_perfect_return();
static_assert(std::is_same_v<decltype(not_perfect_return_show_i), int>);
}