I have wrote the following piece of code
#include <iostream>
const int N = 5;
class X
{
public:
int array[N];
void foo()
{
std::cout << "array size:"<<sizeof(array)/N << std::endl;
}
enum
{
N = 3
};
};
int main()
{
X x;
x.foo();
}
The aforementioned code does not compile with GCC:
<source>:13:8: error: declaration of 'N' [-fpermissive]
N = 3
^
<source>:2:11: error: changes meaning of 'N' from 'const int N' [-fpermissive]
const int N = 5;
^
From my point in compile time the array is defined as an array of five integers and N is defined as 5. How the compiler resolved the name declaration of variables?
Inside the scope of member functions (even those defined inline), the class is considered complete1. As such, using N
there must use the member enumerator. And its value must be 3.
But, that is not the case when declaring class member data. At that point (when specifying array
), the class is not made to be considered complete. So N
can only refer to what was seen previously, which means it must be the global constant.
Clang accepts it, but emits 6
(sizeof(int) * 5 / 3
). GCC (8) doesn't, but it isn't really invalid code. It's just error prone. The way to make better defined would be to move the enumerator to before the array is defined
enum { N = 3 };
int array[N];
... or if we don't, then we can use scope resolution to refer to the "correct N"
sizeof(array) / ::N
Rearranging the class definition would be better, since it will not still remain error prone (we can forget to use the qualified ::N
).
1: From the latest C++ standard draft
[class.mem]/6
A complete-class context of a class is a
- function body ([dcl.fct.def.general]),
- default argument ([dcl.fct.default]),
- noexcept-specifier,
- contract condition ([dcl.attr.contract]), or
- default member initializer
within the member-specification of the class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With