auto in modern c++
@jupp0r
static type checking
checks are performed by the compiler at compile time
correct types are guaranteed for all program inputs
dynamic type checking
checks are performed at runtime
type inference
instead of variable types having to be explicitly declared, the compiler deduces types by usage
// template type deduction - you already know this
template <typename T>
T add(T a, T b) {
return a + b;
}
// auto type deduction - this is new in C++11
auto a = 12;
auto b = 3;
auto c = a + b; // 15
is this static or dynamic typing?
auto a = 12;
auto b = 3;
auto c = a + b;
what's the type of a, b, c?
auto a = 12;
auto b = 3;
auto c = a + b;
AAA
Almost
Always
Auto
AAA
Recommended by
- Herb Sutter
- Scott Meyers
- Andrei Alexandrescu
readability
std::vector<int> numbers = {5, 12, 45, 13};
int sum = 0;
for(std::vector<int>::const_iterator i =
numbers.cbegin();
i != numbers.cend();
i++) {
sum = sum + *i;
}
readability
std::vector<int> numbers = {5, 12, 45, 13};
int sum = 0;
for(const auto i : numbers) {
sum = sum + i;
}
maintainability
We'd like to change the container type of numbers
for(std::vector<int>::const_iterator i =
numbers.cbegin();
i != numbers.cend();
i++) {
sum = sum + *i;
}
maintainability
We'd like to change the container type of numbers
for(const auto i : numbers) {
sum = sum + i;
}
No need to change anything.
correctness
int x; // uninitialized variable,
// reading its value is
// undefined behavior
auto y; // doesn't compile
auto z = 0; // variables declared as auto
// are guaranteed to be initialized
// at compile time
performance
int sumWithAuto(int a, int b) {
auto sum =
[](int x, int y) {
return x + y;
};
return sum(a,b);
}
sumWithAuto(int, int):
lea eax, [rdi + rsi]
ret
recent clang and gcc compile this to
performance
int sumWithoutAuto(int a, int b) {
std::function<int(int,int)> sum =
[](int x, int y) {
return x + y;
};
return sum(a,b);
}
gcc 6.1 compiles this to ...
std::_Function_handler<int (int, int), sumWithoutAuto(int, int)::
{lambda(int, int)#1}>::_M_invoke(std::_Any_data const&, int&&, std::_Any_data const&):
mov eax, DWORD PTR [rsi]
add eax, DWORD PTR [rdx]
ret
std::_Function_base::_Base_manager<sumWithoutAuto(int, int)::{lambda(int, int)#1}>::
_M_manager(std::_Any_data&, std::_Function_base::_Base_manager<
sumWithoutAuto(int, int)::{lambda(int, int)#1}> const&, std::_Manager_operation):
test edx, edx
je .L4
cmp edx, 1
jne .L3
mov QWORD PTR [rdi], rsi
.L3:
xor eax, eax
ret
.L4:
mov QWORD PTR [rdi], OFFSET FLAT:typeinfo for sumWithoutAuto(int, int)::{lambda(int, int)#1}
xor eax, eax
ret
sumWithoutAuto(int, int):
sub rsp, 40
lea ecx, [rdi+rsi]
mov edx, 3
mov rsi, rsp
mov rdi, rsp
mov QWORD PTR [rsp+24], OFFSET FLAT:
std::_Function_handler<int (int, int), sumWithoutAuto(int, int)::
{lambda(int, int)#1}>::_M_invoke(
std::_Any_data const&, int&&, std::_Any_data const&)
mov QWORD PTR [rsp+16], OFFSET FLAT:std::_Function_base::_Base_manager<
sumWithoutAuto(int, int)::{lambda(int, int)#1}>::_M_manager(std::_Any_data&,
std::_Function_base::_Base_manager<sumWithoutAuto(int, int)::
{lambda(int, int)#1}> const&, std::_Manager_operation)
call std::_Function_base::_Base_manager<sumWithoutAuto(int, int)::
{lambda(int, int)#1}>::_M_manager(std::_Any_data&,
std::_Function_base::_Base_manager<sumWithoutAuto(int, int)::
{lambda(int, int)#1}> const&, std::_Manager_operation)
add rsp, 40
mov eax, ecx
ret
But ...
Isn't this just being lazy to declare your types?
Isn't this just you being lazy to declare your types?
No, it's all about
- readability
- maintainability
- correctness
- performance
I'm scared because I dont see what types my variables have
I'm scared because I dont see what types my variables have
You already don't know the exact types that are used in your code, and that's good!
- what type does std::vector<T>::size() return? You don't care as long as it compares to int.
- what type does std::bind return?
- does std::find<std::vector<T>>(...) return the same type as std::vector<T>::end() ? You probably don't care as long as you can compare the two.
You really want to know the types?
IDE is your friend
What about the almost in AAA?
// error, not moveable
auto lock = std::lock_guard<std::mutex>{ m };
// error, not moveable
auto ai = std::atomic<int>{};
Thanks!
Questions?
auto in modern c++
By Jupp Müller
auto in modern c++
- 2,746