Consider the code:
struct Foo
{
const char str[] = "test";
};
int main()
{
Foo foo;
}
It fails to compile with both g++ and clang++, spitting out essentially
error: array bound cannot be deduced from an in-class initializer
I understand that this is what the standard probably says, but is there any particular good reason why? Since we have a string literal it seems that the compiler should be able to deduce the size without any problem, similarly to the case when you simply declare an out-of-class const
C-like null terminated string.
If the compiler was allowed to support what you described, and the size of
str
was deduced to5
,will lead to undefined behavior.
As mentioned in the comments and as answered by @sbabbi, the answer lies in the details
12.6.2 Initializing bases and members [class.base.init]
12.6.2 Initializing bases and members [class.base.init]
So, if there is a non-deleting constructor, the brace-or-equal-initializer is ignored, and the constructor in-member initialization prevails. Thus, for array members for which the size is omitted, the expression becomes ill-formed. §12.6.2, item 9, makes it more explicit where we it specified that the r-value initializer expression is omitted if mem-initialization is performed by the constructor.
Also, the google group dicussion Yet another inconsitent behavior in C++, further elaborates and makes it more lucid. It extends the idea in explaining that brace-or-equal-initializer is a glorified way of an in-member initialization for cases where the in-member initialization for the member does not exist. As an example
is equivalent to
but now we see that if the array size was omitted, the expression would be ill-formed.
But then saying that, the compiler could have supported the feature for cases when the member is not initialized by in-member constructor initialization but currently for the sake of uniformity, the standard like many other things, does not support this feature.
The reason is that you always have the possibility to override an in-class initializer list in the constructor. So I guess that in the end, it could be very confusing.
Notice that replacing
const char
withstatic constexpr char
works perfectly, and probably it is what you want anyway.