I found a strange piece of C++ grammar on CodeSignal:
string r, longestDigitsPrefix(string s)
{
for(auto const c : s)
{
if(isdigit(c))
r += c;
else
break;
}
return r;
}
The first line is defining string r
before the function declaration. Is this valid in modern C++?
The above code compiles and passes all tests in the CodeSignal console, but it produced a compiler error when I tried to compile locally (--std=c++14
).
Is this is valid grammar in modern C++? If so, which standard revision does it comply with?
A variable or a function can be declared any number of times but, it can be defined only once. The above points are summarized in the following table as follows: Declaration. Definition. A variable or a function can be declared any number of times.
What is the difference between declaration and definition in C#? Declaration means that variable is only declared and memory is allocated, but no value is set. However, definition means the variables has been initialized. The same works for variables, arrays, collections, etc.
Function declaration is required when you define a function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
Once something is defined, that also counts as declaring it; so you can often both declare and define a function, class or variable at the same time.
Yeah, C++ grammar is weird. Basically, when it comes to declarations (and only declarations), we have this thing where:
T D1, D2, ... ,Dn;
means ([dcl.dcl]/3):
T D1;
T D2;
...
T Dn;
This will be familiar in the normal cases:
int a, b; // declares two ints
And probably in the cases you've been told to worry about:
int* a, b, *c; // a and c are pointers to int, b is just an int
But declarators can introduce other things too:
int *a, b[10], (*c)[10], d(int);
Here a
is a pointer to int, b
is an array of 10 int
s, c
is a pointer to an array of 10 int
s, and d
is a function taking an int
returning an int
.
However, this only applies to declarations. So this:
string r, longestDigitsPrefix(string s);
is a valid C++ declaration that declares r
to be a string
and longestDigitsPrefix
to be a function taking a string
and returning a string
.
But this:
string r, longestDigitsPrefix(string s) { return s; }
is invalid C++. Function definitions have their own grammar and cannot appear as part of the init-declarator-list.
The definition of that function is also bad, since it's using a global variable to keep track of state. So even if it were valid, longestDigitsPrefix("12c")
would return "12"
the first time but "1212"
the second time...
By reading the ISO C++14 draft N4140 Annex A [gram], I'm pretty sure it's incorrect since I cant find a way to deduce the grammar from a translation unit from
translation-unit -> declaration-seq -> declaration -> block-declaration | function-definition | linkage-specification | ...
function-definition: attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
declarator: ptr-declarator noptr-declarator parameters-and-qualifiers trailing-return-type
But your line is more the comma operator but its grammar is:
expression: assignment-expression | expression , assignment-expression
assignment-expression: conditional-expression | logical-or-expression | assignment-operator | initializer-clause | throw-expression
And there is no way from assignment-expression
to function-definition
Update:
Thanks to Barry, another way to try to buttom-up parse your text is by rather try to get from a init-declarator-list
(which you can get from block-declaration
) to a function-definition
:
init-declarator-list: init-declarator | init-declarator-list , init-declarator
init-declarator: declarator initializeropt
And
declarator: ptr-declarator noptr-declarator parameters-and-qualifiers trailing-return-type
Would allow you a function declaration but not definition. So this odd code would be legal:
#include <string>
using std::string;
string r, longestDigitsPrefix(string s);
string longestDigitsPrefix(string s) {
for(auto const c : s)
{
if(isdigit(c))
r += c;
else
break;
}
return r;
}
int main(int argc, char *argv[]) {
longestDigitsPrefix("foo");
return 0;
}
However I could be wrong, since I'm not used to use the formal grammar of C++, which is normal since it's grammar is very complex, and has some non trivial behaviour.
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