Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize the loop counter declared with the auto keyword?

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.

like image 838
Lone Learner Avatar asked May 24 '18 06:05

Lone Learner


People also ask

What does auto do in a for loop?

Range-based for loop in C++ Often the auto keyword is used to automatically identify the type of elements in range-expression.

What is the auto keyword in C++?

The auto keyword directs the compiler to use the initialization expression of a declared variable, or lambda expression parameter, to deduce its type.

What is the use of auto in STL?

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.


3 Answers

You can use 'decltype(v.size())' to get the correctly type.

for (decltype(v.size()) i = 2; i < v.size(); i++) 
like image 122
nameless1 Avatar answered Nov 15 '22 05:11

nameless1


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++) {
like image 30
songyuanyao Avatar answered Nov 15 '22 07:11

songyuanyao


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.

like image 42
chris Avatar answered Nov 15 '22 07:11

chris