GCC Bugzillaで見つけたC++言語仕様のスミをつつく指摘と、そこから調べてみて分かったC++03とC++11との微妙な差分に関する話題です。
(そもそもmain関数をアクロバティックに使うべきではありませんし、そんな必要もないと思います…)
お話の前提
C++言語仕様では、main
をプログラム内から使用する("odr-used")ことは禁止されています。
もちろん、普通に「プログラム開始時に呼び出されるmain関数を記述する」ことは可能です。ここで言う「使用できない」とは、他関数からmain関数を呼び出し/main関数自身で再帰呼び出しを行ったり、main関数のアドレスを取ったり(&main
)が許可されないことを意味します。この仕様に関してはC++03/C++11で変更はありません。
GCC Bugzillaでの指摘
Bug 41431 - &main should be allowed within unevaluated operands. の要旨:
sizeof演算子のオペランドは"potentially evaluated"では無いから、One Definition Ruleが定めるところの"(odr-)used"ではない。つまりsizeof(&main)
はOKであり、これに対して警告を出すGCCは間違っている。
補足:「sizeof演算子オペランドは"potentially evaluated" expressionではない」「(大まかに)"potentially evaluated" expression内で用いることを"(odr-)used"と定める」は、C++03/C++11で共通の仕様です。
C++03とC++11との差異
確かにISO C++03からWorking Draft N3126までは "The function main shall not be used (3.2) within a program."(§3.6.1 [basic.start.main]) と記述されており、言語仕様上は「"(odr-)used"で無い箇所ならばmain
を使っても良い」、つまり「sizeofでは"(odr-)used"とならないからsizeof(&main)
はOK」と解釈可能です。
一方、C++11(N3337)では "The function main shall not be used within a program" となっています。ここでは定義された用語"odr-used"で明に記述していないため、プログラム内のどこであってもmain
の使用("use")は許可されず、結局は「sizeof(&main)
もNG」と仕様変更されたように読みとれます。
このOne Definition Rule(§3.2 [basic.def.odr])については、仕様上の用語(term)としての"used"と、一般動詞としての"used"が区別できず曖昧であるとの指摘をうけ、N3154 US 19: Ambiguous use of "use"およびN3214 US 19: Ambiguous use of "use" (version 2)で用語"odr-used"が導入された経緯があります。
初版N3154では一旦[basic.start.main]も"odr-used"へと変更する候補にあがっていましたが、続くRev2 N3214では明示的に一般語"used"に変更されています。残念ながら、この変更の根拠までは見つけられませんでした。
おしまい。(どなたか理由までご存知でしたら教えてください)