Here is my code:
#include <iostream>
#include <vector>
void cumulative_sum_with_decay(std::vector<double>& v)
{
for (auto i = 2; i < v.size(); i++) {
v[i] = 0.167 * v[i - 2] + 0.333 * v[i - 1] + 0.5 * v[i];
}
}
void printv(std::vector<double>& v)
{
std::cout << "{";
for (auto i = 0; i < v.size() - 1; i++) {
std::cout << i << ", ";
}
std::cout << v[v.size() - 1] << "}\n";
}
int main()
{
auto v = std::vector<double>{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cumulative_sum_with_decay(v);
printv(v);
}
When I try to compile and run this program, I get these warnings:
$ clang++ -std=c++11 -Wextra foo.cpp && ./a.out
foo.cpp:6:24: warning: comparison of integers of different signs: 'int' and 'std::__1::vector<double,
std::__1::allocator<double> >::size_type' (aka 'unsigned long') [-Wsign-compare]
for (auto i = 2; i < v.size(); i++) {
~ ^ ~~~~~~~~
foo.cpp:14:24: warning: comparison of integers of different signs: 'int' and 'unsigned long'
[-Wsign-compare]
for (auto i = 0; i < v.size() - 1; i++) {
~ ^ ~~~~~~~~~~~~
2 warnings generated.
{0, 1, 2, 3, 4, 5, 6, 7, 8, 8.68781}
How can I initialize these loop counters declared with auto
such that the code is safe and there are no warnings?
Note that although I have a small vector here, I am trying to learn how to write safe code with auto
even when the vector is so large that the value in i
can exceed the range of integers.
Range-based for loop in C++ Often the auto keyword is used to automatically identify the type of elements in range-expression.
The auto keyword directs the compiler to use the initialization expression of a declared variable, or lambda expression parameter, to deduce its type.
The auto keyword is simply asking the compiler to deduce the type of the variable from the initialization. Even a pre-C++0x compiler knows what the type of an (initialization) expression is, and more often than not, you can see that type in error messages.
You can use 'decltype(v.size())' to get the correctly type.
for (decltype(v.size()) i = 2; i < v.size(); i++)
The type of auto
-declared variable is deduced from the initializer. given 2
or 0
it'll be int
.
You could specify the type with explicitly typed initializer. e.g.
for (auto i = static_cast<decltype(v.size())>(2); i < v.size(); i++) {
If you care about matching the type exactly, you can write a helper for this (live example):
// Concepts would help here.
template<typename Cont, typename T>
auto as_size_type(const Cont& cont, T init) {
return static_cast<decltype(std::size(cont))>(init);
}
Usage:
for (auto i = as_size_type(v, 2); i < v.size(); i++) {
v[i] = 0.167 * v[i - 2] + 0.333 * v[i - 1] + 0.5 * v[i];
}
I make use of std::size
to handle differences like arrays vs. classes that have a ::size_type
, but it's possible to move that responsibility to this helper if std::size
isn't available. Similarly, the automatic return type deduction can use decltype
etc. instead in C++11.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With