conversion from 'unsigned int' to 'int' requires a narrowing conversion - c++

My code includes the following, and I get the error message above based on the last line below.
struct List {
int word_i;
int mod_i;
char mod_type;
char mod_char;
};
struct Morph {
Options mode;
deque<List> search_list;
vector<string> dictionary;
vector<bool> discovered;
string output;
int sel_word_i = 0;
bool end_found = 0;
};
// later on in a function:
morph->search_list.push_back({ morph->dictionary.size() - 1, 0, 0, 0 });

You can replace the last line with:
morph->search_list.emplace_back( morph->dictionary.size() - 1, 0, 0, 0 );
Thus the object is created not through brace initialization which does not allow narrowing conversion.
The narrowing conversion is from the return value of the call to size which returns std::size_t which is unsigned.
For why size() - 1 is not converted to a signed value see: C++ Implicit Conversion (Signed + Unsigned)

When and after you applied what Amir suggested, you may get an error saying something like, "this function does not take (3) arguments." To fix that you'll have to declare a constructor in the class, which you used for your vector, that takes that particular number of arguments. From what I understood when you replace push_back(); with emplace_back();the compiler thinks that you're trying to pass some variables to the constructor, which are the supposed arguments.

Related

Query about function overloading

When using function with same name, parameter list must differ(either in type of parameter or number of parameters used). I was just practicing with this concept. I wrote the following code.
#include <iostream>
int myFunction(int n)
{
return 2*n;
}
float myFunction(float n)
{
return 3*n;
}
int main()
{
int x=myFunction(3);
std::cout << x;
return 0;
}
I thought I will get error because compiler will get confused which myFunction to use because I directly pass the value 3 without storing it in a particular type of variable . But I got output 6. So I tried the following code.
#include <iostream>
int myFunction(int n)
{
return 2*n;
}
float myFunction(float n)
{
return 3*n;
}
int main()
{
float x=myFunction(3.3);
std::cout << x;
return 0;
}
As previous one worked fine, I thought this will work fine too, as 3.3 is not integer so it's clear which one to call, but this time I got compiler error saying it's ambiguous.
So my doubt is why first code worked but not second one.
The process of selecting the overload during a call is called overload resolution. Given the types of the arguments, the compiler selects the best viable function from the list of candidates - the one that can be invoked with the least amount of promotions and implicit conversions.
In the first case the first one myFunction(int) requires 0 conversions for an int argument (3), and the second one requires one conversion (int -> float), so the first one is selected as the best candidate.
In the second case a double argument (3.3) requires a conversion to either int or float, so there is no clear winner and thus the call is ambiguous.
The fix could be to use a float argument (3.3f) or change myFunction(float) to myFunction(double).
Literals have types too. As integer literal 3 is of type int, then the 1st overload is selected.
As floating point literal 3.3 is of type double (but not float; with the suffix f like 3.3f the type is determined as float), the calling is ambiguous because it could convert to both int and float implicitly.
try this:
int x=myFunction(int(3));
float x=myFunction(float(3.3));

Are bool arrays treated differently in terms of decaying?

Consider an example where I want to create an array of arrays of bool:
int main() {
using type = bool[1];
bool a1[1] = {true};
bool a2[1] = {true};
bool a3[1] = {true};
type block_types[3] = {{a1}, {a2}, {a3}};
}
This code compiles for Clang 7.0.0, GCC 8.2 and MSVS v19.16.
Now, let's change bool to int:
int main() {
using type = int[1];
int a1[1] = {1};
int a2[1] = {1};
int a3[1] = {1};
type block_types[3] = {{a1}, {a2}, {a3}};
}
Now, the code stops compiling on any of those compilers, with errors similar to:
error: invalid conversion from 'int*' to 'int' [-fpermissive]
type block_types[3] = { {a1}, {a2}, {a3}};
^
Note: this exact error message comes from GCC 8.1.
Why is that? Why are bool[]s treated differently than int[]s? What's the rationale behind this?
In the first, block_types is an array of three arrays of one boolean. Each of the inner blocks in your initializer needs to provide a boolean value. You've given a pointer for each one, and pointers will convert to bool.
In the second, block_types is an array of three arrays of one integer, and each inner block of your initializer needs to provide an integer value. You have again given pointers, and they don't convert to integer.
So, no: the arrays are decaying on the same rules, but resulting pointer conversions distinguish the examples.

How to pass specificly sized array as argument?

I have a function that generates a safe input with error handling so it's cleaner to input numbers (int). But I want one of the argument to be an optional array of length 2 that contains the boundaries of the wanted variable input.
Here's what I have for now :
//function prototype
void input_number(int* variable, string text = "Input : ", int boundaries[2] = NULL);
//function call
int variable;
input_number(&variable, "Choose a number between 0 and 10 : ", {0, 10});
This doesn't work, throwing the error cannot convert '<brace-enclosed initializer list>' to 'int*' for argument '3' to 'void input_number(int*, std::__cxx11::string, int*)'
How can I pass an array of length 2 to the function?
Also, is int[] = NULL correct for a default array value or am I totally wrong?
The error message explains the problem - an array is converted to a pointer (to the first element) when passed as an argument to a function.
One solution would be to pass a struct type that has two members, and give that a default value. An example would be, since std::array is actually a templated structure
void input_number(int* variable, std::string text = "Input : ", const std::array<int, 2> &bounds = {});
int variable;
input_number(&variable, "Choose a number between 0 and 10 : ", {0, 10});
However, any data structure that can store two values, and be constructed using an initializer_list<int>. There are other examples of such types in the standard library - std::array is not the only one.
Personally, I'd also omit the first argument, and have it as a return value
int input_number(std::string text = "Input : ", const std::array<int, 2> &bounds = {});
// to call
int variable = input_number("Choose a number between 0 and 10 : ", {0, 10});
This has the problem of the function not being able to report an error (other than by throwing an exception), but so does your approach.
Personally, I also wouldn't pass the boundaries as default arguments. I'd simply do it with function overloading;
int input_number(std::string input, int lower_bound, int upper_bound)
{
// do whatever you want
}
int input_number(std::string input)
{
return input_number(input, std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
}
which forces the caller to either provide no arguments after the first (in which case, default bounds are used), or two (which specify the bounds) - passing only one additional argument would be a diagnosable error. The only difference from what you've asked is that this does not require (implicitly or explicitly) constructing an array or other data structure to call the function - which is arguably easier for the caller to deal with.
Try this:
void input_number(int* variable, string text = "Input : ", std::array<int, 2> boundaries = {});

Unsigned Char Template Value Overflow

I'm using the following template to encode unsigned char values:
template <unsigned char val>
struct Cell {
enum { value = val };
using add = Cell<val + 1>;
using sub = Cell<val - 1>;
};
I expected sub to behave like a standard unsigned char variable regarding overflow:
unsigned char x = 0;
x - 1; // 255
But instead I get a compiler error in Clang:
using cell = Cell<0>;
cell::sub::value; // Error here.
Non-type template argument evaluates to -1, which cannot be narrowed to type 'unsigned char'
Is overflow handled differently in template contexts?
val - 1 is an int on your platform, on account of the usual arithmetic conversions. There is no sensible meaning for a template parameter of type unsigned char to be given an int argument.
Simply make sure that your template argument has the desired type:
using sub = Cell<static_cast<unsigned char>(val - 1U)>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^
(Using an unsigned int literal means that the usual conversions produce an unsigned int, which has well-defined narrowing semantics.)

C++ Function Overloading Similar Conversions

I'm getting an error which says that two overloads have similar conversions. I tried too many things but none helped.
Here is that piece of code
CString GetInput(int numberOfInput, BOOL clearBuffer = FALSE, UINT timeout = INPUT_TIMEOUT);
CString GetInput(int numberOfInput, string szTerminationPattern, BOOL clearBuffer = FALSE, UINT timeout = INPUT_TIMEOUT);
I can't understand how could string be equal to long?
I'm using Visual C++ 6 (yep I know its old, I'm working on legacy code, so I'm pretty much helpless)
EDIT: The line of code that is triggering the error is
l_szOption = GetInput(13, FALSE, 30 * 10);
The problem is caused by the fact that you are supplying the timeout argument as a signed integer value, which has to be converted to an unsigned one for the first version of the function (since the timeout parameter is declared as UINT).
I.e. the first version of the function requires a conversion for the third argument, while the second version of the function requires a conversion for the second argument (FALSE, which is just 0, to string). In this case neither function is better than the other and overload resolution fails.
Try explicitly giving the third argument the unsigned type
l_szOption = GetInput(13, FALSE, 30U * 10);
or
l_szOption = GetInput(13, FALSE, (UINT) 30 * 10);
(whichever you prefer) and the code should compile as expected.
In other words, the compiler is absolutely right to complain about your code. Your code is indeed broken. The problem in your code has exacty the same nature as in the following simple example
void foo(int i, unsigned j);
void foo(unsigned i, int j);
int main() {
foo(0, 0);
}
This code will also fail to compile for precisely the same reason.
GetInput(13, FALSE, 30 * 10);
My guess is that
FALSE ==> o ==> NULL is getting converted to std::string(NULL)
hence, it cannot determine which method to instantiate.
T0 prove this check this :
GetInput(13, TRUE, 30 * 10); //it works
You are possibly passing that function a second parameter that is neither a BOOL, nor a string, but a type that could be implicitly converted to either.
A character pointer, for example.
To resolve the ambiguity when you call the function either cast the second parameter to BOOL or use string("whatever") if that is indeed std::string.
Consider following case :
BOOL is typedef of int.
GetString(10,'a'); // compiler get confused in resolving the function
whether 'a' is to be converted to BOOL or string ???
When you make function call give proper argument by using static_cast to make desired function to call.
char ch = 'a';
GetString(10,static_cast<BOOL>(ch)); // calls function with 2nd argument as BOOL
GetString(10,static_cast<string>(ch)); //calls function with 2nd argument as string