auto¶

  • Prior to C++11, the keyword auto was a storage class specifier
    • But rarely used
void f() {
    auto int i = 42;
}

auto variable declarations¶

auto can be used in a variable declaration.

  • auto alone will always deduce to an object type (not a reference, or const type)
const int& a = 42;
auto b = a;

print_type_name<decltype(a)>();
print_type_name<decltype(b)>();
  • cv-qualifiers and reference modifiers can be combined with auto
const auto c = b;
const auto& d = b;

print_type_name<decltype(c)>();
print_type_name<decltype(d)>();
  • decltype(auto) can be used to declare a variable which matches the expression type
decltype(auto) e = a;

print_type_name<decltype(e)>();
  • auto&& is a forwarding reference
  • decltype is used with the std::forward template argument
namespace {

instrumented some_function() { return instrumented(); }
void some_sink(instrumented) { }

} // namespace
auto&& q = some_function();
some_sink(forward<decltype(q)>(q));

auto function results¶

C++11 added trailing return types. This allows a return type which is dependent on an argument type.

namespace {

int function_a();
auto function_b() -> int; // same signature as function_a

template <class T, class U>
auto add(T a, U b) -> decltype(a + b) {
    return a + b;
}

} // namespace
  • C++14 allows the return type to be omitted for template and inline functions.
inline auto mixed_add(unsigned a, signed b) {
    return a + b;
}

auto r = mixed_add(42, -1);
print_type_name<decltype(r)>();
cout << r << "\n";
  • Using decltype(auto) for the return type preserves references and cv-qualifiers
namespace {

vector<int> v = { 0, 1, 2, 3 };

inline decltype(auto) back() {
    return v.back();
}

} // namespace
type_name<decltype(back())>();

auto template parameters (C++17)¶

  • C++17 adds auto template parameters.
namespace cpp14 {

template <class T, T N>
struct integral_constant {
      static constexpr T value = N;
};

using true_type = integral_constant<bool, true>;

}
  • In C++17 this can be implemented without specifying the type.
template <auto N>
struct integral_constant {
      static constexpr decltype(N) value = N;
};

using true_type = integral_constant<true>;

structured bindings (C++17)¶

  • structured bindings allow you to construct a set of objects from an array, tuple, type like, or class/struct public members
auto [first_name, last_name] = make_pair("Jane"s, "Smith"s);
cout << last_name << ", " << first_name << '\n';

Smith, Jane
  • simple handling of functions returning structures
int a[] = { 0, 3, 4, 5, 5, 5, 6, 6, 7 };

for(auto [f, l] = equal_range(begin(a), end(a), 5); f != l; ++f) {
    cout << *f << '\n';
}

5
5
5
  • deduction rules are different from other uses of auto
    • each element is deduced to decltype(e) where is the corresponding member
int a = 1, b = 2;
auto [x, y] = tie(a, b);

x = 42;
cout << a << endl;

42
print_type_name<decltype(x)>();

int&
  • can use const and reference qualifiers with structured bindings
int a = 1, b = 2;
const auto& [x, y] = tie(a, b);

a = 42;
cout << x << endl;

42

limitations of structured bindings¶

  • no way to ignore an element
  • no way to reorder, or bind by name

auto lambda arguments (covered in lambda section)¶

Issue¶

Qualify with references appropriately¶

vector<instrumented> w(5);
for (auto e : w) {
    // do something
}
for (const auto& e : w) {
    // do something
}

recommendations for auto variables¶

  • Use auto where required
  • Use auto where complex names do not add clarity
for (typename vector<my_class>::const_iterator f = v.begin(), l = v.end;
     f != l; ++f) {
for (auto f = v.begin(), l = v.end(); f != l; ++f) {
  • auto can make code less brittle to small changes (like size of integral result)

  • Use for structured binding (better than any alternative)

  • Otherwise it becomes a matter of taste. Some people recommend using auto almost never, some people recommend using auto always. If it makes your code more clear, use it, otherwise do not, but avoid bikeshedding.

recommendations for auto function results¶

  • Use trailing result types except for bool and void
auto some_function() -> some_type;
bool is_something();
void got_nothin();
- code aligns better, and it is easier to read
- avoids having trailing result types breaking the style when required
  • Don't use auto results unless required, or naming the type adds nothing
auto some_function() {
    //...
    return f(g(a + y)); // don't make me figure out this type!
}
- Nearly every time I've omitted the result, I've regretted it

homework¶

  • Experiment with auto variables and trailing return types in your project
  • Find some cases where you think it improves the code readability
  • Find some cases where you think it hinders the code readability
  • Write up examples of both on the wiki