2

please help a c++ newbie understand what is going wrong here. I got compile error message of Non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list on leetcode web and my local ubuntu terminal, but it works perfectly fine on my CLion IDE. Also could explain why I got the error and how to solve it?

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{
    vector<vector<int>> heights({{1, 2, 2, 3, 5}, {3, 2, 3, 4, 4}, {2, 4, 5, 3, 1}, {6, 7, 1, 4, 5}, {5, 1, 1, 2, 4}});
    deque<vector<int>> dq;

    for (int i=0;i<heights.size();i++){
        dq.push_back({i,heights[0].size()-1});
    }


    for (auto vec: dq){
        if (vec.empty())
            cout<< "vec is empty";
        else
            cout<<vec[0]<< " "<< vec[1]<<endl;
    }
    return 0;
}

Soon as switch to pair from vector<int>, the error is gone. It's quite confusing to a newbie like me. Please shed some light on this.

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int main()
{
    vector<vector<int>> heights({{1, 2, 2, 3, 5}, {3, 2, 3, 4, 4}, {2, 4, 5, 3, 1}, {6, 7, 1, 4, 5}, {5, 1, 1, 2, 4}});
    deque<pair<int, int>> dq;

    for (int i=0;i<heights.size();i++){
        dq.push_back({i,heights[0].size()-1});
    }


    for (auto [u,v]: dq){
        cout<<u<< " "<< v<<endl;
    }
    return 0;
}
Albert G Lieu
  • 891
  • 8
  • 16
  • For those who want to close this question, I can delete/close it, but could you please give any help. – Albert G Lieu Jan 06 '22 at 23:59
  • 1
    Unrelated: `#include ` and `#include ` in the same file suggests you don't know what `#include ` does and how it should be used. [Here's some reading to help you out with that](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) – user4581301 Jan 06 '22 at 23:59
  • 1
    If you are compiling with GCC, add the `-pedantic-errors` flag to the compiler invocation and it will produce the same error. Without that flag GCC will treat it as just a warning (which I think it should have given you). – user17732522 Jan 07 '22 at 00:04
  • Unrelated: `heights[0].size()-1` will turn into a very large number if `heights[0]` is empty. `size` returns an unsigned integer and 0-1 in unsigned arithmetic will roll around to the maximum possible value rather than provide -1. – user4581301 Jan 07 '22 at 00:05
  • @user4581301 In this case since the very large number is converted into a signed integer of a smaller rank (equal rank would also work), it will convert to -1 (guaranteed by standard since C++20; reliable assumption on 2's complement systems before that). – eerorika Jan 07 '22 at 00:19

2 Answers2

3

When you use brace-initialization, it is forbidden for a narrowing conversion to be used to convert from the type of the value in the braced list to the type that the constructor actually requires. heights[0].size()-1 has type size_t, and the constructor of std::vector<int> takes std::initializer_list<int>. Usually, int cannot represent all values of type size_t, which means that size_t to int is a narrowing conversion. You can fix this using an explicit cast:

dq.push_back({i,static_cast<int>(heights[0].size()-1)});

When the type being constructed is std::pair<int, int>, it is a different story. No conversion actually occurs when calling the constructor; instead, the following constructor is called:

template< class U1, class U2 >
constexpr pair( U1&& x, U2&& y );

See cppreference.

Internally, presumably in the constructor initializer list, the constructor will convert size_t to int, but this will not be done inside braces, so it's legal.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
2

C++ language doesn't allow narrowing implicit conversions within a braced initialiser list (unless the value compile time constant). This protects you from making certain obvious mistakes.

This is the braced initialiser list: {i,heights[0].size()-1}.

A narrowing conversion is a conversion into a type that cannot represent all values of the source type. The type of the expression heights[0].size()-1 was on your system unsigned long which on your system can represent values that the int type cannot represent.

You can fix the issue by doing an explicit conversion. It is safe in this case because we know that the size is non-zero, and doesn't exceed the maximum value representable by int:

static_cast<int>(heights[0].size()-1)
eerorika
  • 232,697
  • 12
  • 197
  • 326