Home > Software engineering >  warning using std::accumulate(v.begin(), v.end(), 0);
warning using std::accumulate(v.begin(), v.end(), 0);

Time:11-17

Why do I get a warning C4244 '=': conversion from '__int64' to '_Ty', possible loss of data? Also, auto instead of LONGLONG produces this warning.

std::vector<LONGLONG>& v = m_vecEstimatedTime;
LONGLONG nEstimatedTimeTotal = std::accumulate(v.begin(), v.end(), 0);  //  warning C4244  '=': conversion from '__int64' to '_Ty'

CodePudding user response:

The return type, and the summary value's type of std::accumulate is determined by the initial value being passed. For 0 it'll be int.

If the type is supposed to be LONGLONG, you can specify the initial value as:

LONGLONG nEstimatedTimeTotal = std::accumulate(v.begin(), v.end(), static_cast<LONGLONG>(0));

CodePudding user response:

std::accumulate adds up values in the range. Essentially, it looks like this:

template <class Iter, class Accum>
Accum accumulate(Iter first, Iter last, Accum x) {
    while (first != last)
        x  = *first  ;
    return x;
}

The problem that the compiler is warning you about is that in accumulate(v.begin(), v.end(), 0) that internal sum is adding LONGLONG values to an int value; that's where the possible loss of precision occurs. auto doesn't remove that warning, because it's not just nEstimblahblah that's the culprit; the internal type also loses precision.

To fix it, in this case the third argument should have the same type as the things being added. The obvious way of doing that is with explicit types:

LONGLONG total = std::accumulate(v.begin(), v.end(), static_cast<LONGLONG>(0));

The drawback with this approach is that everything is hardcoded; if you want to change the type of the elements of the vector you have to change it in three places. You could use a typedef for the element type:

typedef LONGLONG elem_t;
std::vector<elem_t>& v = whatever;
elem_t total = std::accumulate(v.begin(), v.end(), static_cast<elem_t>(0));

Or, for even more flexible code, typedef the whole thing:

typedef std::vector<LONGLONG> ctr_t;
typedef typename ctr_t::value_type elem_t;
ctr_t& v = whatever;
elem_t total = std::accumulate(v.begin(), v.end(), static_cast<elem_t>(0));

With that version you can change the element type without changing the rest of the code, and you can change the container type without changing the rest of the code. On the other hand, this version is more verbose, and perhaps too flexible.

  •  Tags:  
  • c
  • Related