CodeSignal でC++文法の奇妙な部分を見つけました:
string r, longestDigitsPrefix(string s)
{
for(auto const c : s)
{
if(isdigit(c))
r += c;
else
break;
}
return r;
}
最初の行は、関数宣言の前にstring r
を定義しています。これは最新のC++で有効ですか?
上記のコードは、CodeSignalコンソールですべてのテストをコンパイルしてパスしますが、ローカルでコンパイルしようとするとコンパイラエラーが発生しました(--std=c++14
)。
これは最新のC++で有効な文法ですか?もしそうなら、それはどの標準改訂に準拠していますか?
ええ、C++の文法は奇妙です。基本的に、declarations(および宣言のみ)に関しては、次のようになります。
_T D1, D2, ... ,Dn;
_
( [dcl.dcl]/ )を意味します:
_T D1;
T D2;
...
T Dn;
_
これは通常のケースではおなじみでしょう:
_int a, b; // declares two ints
_
そしておそらくあなたが心配するように言われた場合には:
_int* a, b, *c; // a and c are pointers to int, b is just an int
_
しかし、宣言者は他のものも導入することができます:
_int *a, b[10], (*c)[10], d(int);
_
ここで、a
はintへのポインター、b
は10の配列int
s、c
は10の配列へのポインターint
s、およびd
はint
を取り、int
を返す関数です。
ただし、これはonlyが宣言に適用されます。したがって、この:
_string r, longestDigitsPrefix(string s);
_
r
をstring
として宣言し、longestDigitsPrefix
をstring
を取り、string
を返す関数として宣言する有効なC++宣言です。
でもこれは:
_string r, longestDigitsPrefix(string s) { return s; }
_
無効なC++です。関数定義には独自の文法があり、init-declarator-listの一部として表示できません。
グローバル変数を使用して状態を追跡しているため、その関数の定義も不適切です。したがって、それが有効であっても、longestDigitsPrefix("12c")
は最初は_"12"
_を返しますが、2回目は_"1212"
_を返します...
ISO C++ 14ドラフトN4140附属書A [グラム]を読むことで、翻訳単位から文法を推測する方法が見つからないので、間違いだと思います。
翻訳単位->宣言-シーケンス->宣言->ブロック宣言|関数定義|リンケージ仕様| ...
function-definition:attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
宣言子:ptr-declarator noptr-declarator parameters-and-qualifiers trailing-return-type
しかし、あなたの行はもっとコンマ演算子ですが、その文法は次のとおりです:
式:割り当て式|式、代入式
割り当て式:条件式|論理OR式|代入演算子|初期化子節|スロー式
そして、assignment-expression
からfunction-definition
への道はありません
更新:バリーのおかげで、テキストを解析するもう1つの方法は、init-declarator-list
(block-declaration
から取得できます)からfunction-definition
に取得することです。
init-declarator-list:init-declarator | init-declarator-list、init-declarator
init-declarator:宣言子のinitializeropt
そして
宣言子:ptr-declarator noptr-declarator parameters-and-qualifiers trailing-return-type
関数宣言はできますが、定義はできません。したがって、この奇妙なコードは合法です:
#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;
}
ただし、C++の正式な文法を使用するのは慣れていないため、間違っている可能性があります。これは、文法が非常に複雑であり、些細な動作がないため、これは正常です。