@EzoeRyou @cpp_akira クラス内部での置換は immediate context はないからです。 この例は有名だと思ったんですが、もしかしたら間違ってるのかもしれないので、ちょっと調べなおしてみますね
— 銀天すばる(残念なC++er)@実際群馬 (@SubaruG) June 4, 2012
まさかそんなことはないだろう。それなら以下のコードはコンパイルエラーになってしまうはずではないかと思って試したところ、本当にコンパイルエラーになってしまった。なるほど、たしかに正しい。
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を実現するべく、その他の場合もエラーではないとした。
しかし、まさかこんな落とし穴が残ってい用途は思わなかった。これは説明に窮する。もちろん、定義はしっかりしているが、なぜこんなルールになっているのかという疑問が沸く。なぜだ。
> なぜだ。
ReplyDeletehttp://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.
などなど。
おお、読んでみます。
ReplyDeletepaperの山からどうやって探しだそうか、
いっそのこと、人に聞くべきかと思案していたところです。
まあ、予想通り実装上の都合かな。
ReplyDelete完全に副作用に属するかどうかを判定するのは難しいという事か。