2010-10-25

ややこしいnoexcept

MLに面白い話題が上がっていたので紹介する。

noexceptには、二つの意味がある。

1. 例外指定としてのnoexcept

void f() noexcept ; // noexcept(true)と同じ
void g() noexcept(true) ; // 例外を投げない
void h() noexcept(false) ; // 例外を投げる

この場合、文法は、noexcept( 定数式 )という文法になる。定数式がtrueと評価されれば、無例外といういみである。

2. noexcept演算子

void f() ;
void g() noexcept ;

int main()
{
    noexcept( f() ) ; // false
    noexcept( g() ) ; // true
}

この場合、文法は、noexcept( 未評価式 )となる。未評価式が例外を投げる可能性があれば、falseを返す。例外を投げないと保証できる場合は、trueを返す。例外を投げる可能性というのは、throw式が含まれているかや、noexcept(true)と指定されていない関数を呼び出すかどうかで判断される。たとえ、実際にはthrow式が含まれていなくても、無例外指定がされていない関数の呼び出しは、falseと評価される。noexcept演算子は、定数式である。

さて、以下の例を考えてみよう。

void f() noexcept( noexcept( g() ) ) ;

これはどういう意味かというと、g()という未評価式が、例外を投げる可能性がなければ、関数fは無例外指定されるという意味である。一方、

void f() noexcept( g() ) ;

これは、g()という定数式が、trueと評価された場合に、関数fは無例外指定になるという意味である。もちろん、g()という式が定数式でなければ、エラーとなる。

この文法はどう考えてもややこしくないか。

実は、以下のような文法も考慮されていたらしい。

void f() noexcept if true ;

ここでは、ifというキーワードを使うことによって、次に定数式を指定している。しかし、noexcept(true)の方が分かりやすいという意見の方が多かったため、こうなった。また、別の拡張で、似たような文法を使いたい時に困るという意見もあった。別の拡張というのは、ほかでもない、明示的なSFINAEである。

No comments: