blog2018-04-28complexの引数に暗黙の型変換を走らせるためにTMPした話C++競プロやってたらなんか引っかかったので、少しはC++知ってたほうがいいかなとちょっと掘り下げてみた話です。以下の二つのコードがあり、片方は普通に動くのですが、片方はコンパイルエラーを起こします。std::endl;}普通に動いてくれるのは、下のコードです。^とあり、まぁ型があってないねってことっぽいです。complex型について'*'の定義をオーバーロードしている文が3つ見えますが、どれにも該当してないぞと言われています。intはdoubleに暗黙に型変換してくれるんじゃないのかという気持ちになるんですが*1、「これらの演算子は関数テンプレートであるため、」「暗黙の型変換は行われない」そうです*2。minとかmaxでintとdouble入れるとエラー吐かれるのと同じやつのようです。(2)となっており、(1)の定義では引数の型がテンプレートではないため(つまり今回では普通にdoubleを受け取る関数)、引数としてintを渡しても暗黙の型変換が普段のように行われます。-0x18(%ebp),%eaxとなっており、そうなっていることが確認できました。この差が生まれたかというと、今はcomplex<T>型とT型の掛け算を許しているわけですが*3、'*'の場合は2引数のうち必ず片方はcomplex<T>型であるため、関数テンプレートで定義をする必要がある一方、'*='の場合は引数がT型のみである場合があるため、関数テンプレートを使う必要がなく、暗黙の型変換が行えるような状況になっています。ここから先は、関数テンプレートでも、テンプレートパラメータを優先して型を決めればその先は暗黙の型変換が行えるような気がするという発想のもと、試行錯誤するのを学科同期のプロ*4に協力を仰ぎながらしてみたものです。std::complexでの'*'operatorのソースコードを見てみます。__t;}こんな感じにすれば'*='に処理を流すことができるので暗黙の型変換が_Up型についてうまく動きそうです。これはよくなくて、上記のコードを第一引数と第二引数を逆転させたものも追加したとき以下のようなコードでまずいです。std::endl;}今はわかりやすくするために'*'の代わりに'^'を使っていますが、これはエラーが吐かれます。^~~~~~~~つまり、複数の関数の引数の型にマッチするためどの関数を呼べばよいのか判断がつかなくなりコンパイルが通りません。これをどうやって解決するかですが、引数の両方がcomplex型の場合と片方だけがcomplex型の場合に分けて適切な関数を呼べればこの問題が解決することがわかります。型で場合分けと聞いてまぁ何が登場するかというとテンプレートメタプログラミングですね。いうわけで、C++にお強い例のとんがりくんがほぼ一人で書いてくれました。一応、'*'の代わりに自分で実装した'*'として'^'を使っています。0;}declvalの便利さなどが実感できるコードになってます。僕たちが確認した範囲では、ちゃんと動いているように見えました。両方ともcomplexで型が一致している場合は普通に動き、片方がcomplexの場合はもう一つの方の型をTにキャストできたらキャストして計算し、これら以外の場合はエラーを吐きます。実際これはすごく便利だと思うのでstdでもこう実装してくれていると嬉しいと思うのですが、こうなっていないからには既に何かしらの形で存在しているのか、この方法に問題があるのかだと思うので、有識者の方は教えていただけると嬉しいです。何かわかったら追記するかもです。検索はてなブログをはじめよう!gasinさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。