Stack Overflow Asked by Zorglub29 on February 23, 2021
From what I understand, {}
is a way to initialize variables with some "safety" advantages over other methods, such as forbidding narrowing:
int some_int_a = 1.2; // narrows
int some_int_b (1.2); // narrows
int some_int_c {1.2}; // does NOT compile, cannot narrow
So far so good. The thing I recently discovered, that I do not understood fully, is when does this sort of check happen? For example, in the following code:
#include <iostream>
class ExClass{
private:
const int i;
public:
ExClass(int i=0): i{i} {
// needed even if empty
}
void print(void){
std::cout << "const int i = " << i << std::endl;
}
};
int main(void)
{
ExClass ex_a (2.3); // narrows! this was surprising to me, I (probably naively)
// expected i{i} in the constructor to forbid this.
ex_a.print();
ExClass ex_b {2.3}; // does not compile
ex_b.print();
return 0;
}
I suppose this means that in the case of ex_a
, first an intermediate int
is created fully with a narrowing conversion, then this intermediate int
is used to bracket-initialize i
in the constructor. While in the second case, the intermediate int
cannot be bracket-initialized with a conflicting input, is that right?
Is there a way to write things in such a way that there is no "intermediate" narrowing, so that the class bracket initialization detects the faulty input?
What happens here is that the constructor:
ExClass(int i=0): i{i}
Takes an int
parameter, and narrowing here:
ExClass ex_a (2.3);
is fine. Once you are in the contructor, i
is an int
(the parameter, not the member). Hence there is no narrowing in i{i}
(it is int
to int
). You do get the error when you change your constructor to:
ExClass(double i=0): i{i} { }
Because now there is actually narrowing in i{i}
.
Note that gcc only issues a warning with default settings and needs -pedantic-errors
to recognize it as error. Thanks to Remy for pointing out that it actually is an error, not a warning.
Correct answer by largest_prime_is_463035818 on February 23, 2021
Is there a way to write things in such a way that there is no "intermediate" narrowing, so that the class bracket initialization detects the faulty input?
You can make the constructor take a template parameter so it takes on the type of whatever the caller passes in, eg:
#include <iostream>
class ExClass{
private:
const int i;
public:
template<typename T>
ExClass(T i=T{}): i{i} {
// needed even if empty
}
void print(void){
std::cout << "const int i = " << i << std::endl;
}
};
int main(void)
{
ExClass ex_a (2.3); // should not compile!
ex_a.print();
ExClass ex_b {2.3}; // should not compile!
ex_b.print();
return 0;
}
Unfortunately, GCC allows this narrowing by default, issuing a warning rather than an error (use -pedantic-errors
to force an error):
warning: narrowing conversion of 'i' from 'double' to 'int' [-Wnarrowing]
Clang issues an error, though:
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
Answered by Remy Lebeau on February 23, 2021
Brace initialization (since C++11) prevents narrowing. As cppreference states under Narrowing conversions:
list-initialization limits the allowed implicit conversions by prohibiting the following:
- conversion from a floating-point type to an integer type
- conversion from a long double to double or to float and conversion from double to float, except where the source is a constant expression and overflow does not occur
- conversion from an integer type to a floating-point type, except where the source is a constant expression whose value can be stored exactly in the target type
- conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where source is a constant expression whose value can be stored exactly in the target type
- conversion from a pointer type or pointer-to-member type to bool (since C++20)
So prefer brace initialization over the alternatives.
Answered by jignatius on February 23, 2021
The debugger would probably show you this very quickly! Look at what you are doing: if(ExClass(next) == false || opening_brackets_stack.empty() == false)
What is the type of ExClass when you try to compare it with a close bracket
Hint: think about when you create each new instance of a Bracket. Are they all brackets? Are they all open brackets?
Answered by Drian La on February 23, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP