2012-06-04

インスタンス化による副作用としてのインスタンス化はimmediate contextではない

まさかそんなことはないだろう。それなら以下のコードはコンパイルエラーになってしまうはずではないかと思って試したところ、本当にコンパイルエラーになってしまった。なるほど、たしかに正しい。

template < typename T >
struct X
{
    using type = T ; 
} ;

template < >
struct X<int> { } ;

template < typename T >
struct Y
{
    using type = typename X<T>::type ;
} ;

template < typename T, typename Dummy = typename X<T>::type >
void f(T) {}
void f( short ) { }

template < typename T, typename Dummy = typename Y<T>::type >
void g(T) {}
void g( short ) { }

int main()
{
    f( 0 ) ; // OK
    g( 0 ) ; // Can be Error
}

関数fは、Dummyのsubstitutionに失敗するので、通常の関数が選ばれる。関数gは、クラステンプレートをひとつ挟んでいる。こうすると、クラステンプレートYのインスタンス化は、クラステンプレートXのインスタンス化をもたらす。このインスタンス化は、immediate contextではないので、SFINAEには引っかからず、ill-formedとなる。

なるほど、これは気が付かなかった。

問題は、なんでこうなっているのかということだ。しかも、これがエラーかどうかは、規格上は定められていないのだ。なぜならば、

The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc.Such side effects are not in the “immediate context” and can result in the program being ill-formed.

§ 14.8.2 paragraph 8 note.

"can result in the program being ill-formed"となっている。つまり、規格上、エラーでなくても構わないのだ。

SFINAE周りは、だいぶコンパイラーごとの差異が激しかった部分である。C++03までは、ホワイトリスト方式で、エラーとはならない場合を列挙していた。C++11では、これを完全するため、従来のホワイトリストを残しつつ、文字通り、substitutio failure is not an errorを実現するべく、その他の場合もエラーではないとした。

しかし、まさかこんな落とし穴が残ってい用途は思わなかった。これは説明に窮する。もちろん、定義はしっかりしているが、なぜこんなルールになっているのかという疑問が沸く。なぜだ。

3 comments:

  1. > なぜだ。

    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html
    via http://www.google.co.jp/search?q=site%3Awww.open-std.org%2FJTC1%2FSC22%2FWG21+%22can+result+in+the+program+being+ill-formed%22
    > "Speculative compilation" sounds like an easy way out, but in practice compilers can't do that.
    などなど。

    ReplyDelete
  2. おお、読んでみます。
    paperの山からどうやって探しだそうか、
    いっそのこと、人に聞くべきかと思案していたところです。

    ReplyDelete
  3. まあ、予想通り実装上の都合かな。
    完全に副作用に属するかどうかを判定するのは難しいという事か。

    ReplyDelete

You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.