わくわく技術ブログ

プログラミング・統計・機械学習

VS2015ならconstexprでコンパイル時演算でき…ない??

事の経緯

前回・前々回と、C++のTemplateを使った処理について書きました。 そして、以前知人が

まだ実行時ソートで消耗してるの? 〜ScalaでHListを使ったコンパイル時クイックソート 〜 (前編) - だいたいよくわからないブログ

とかいう記事を書いてるのを思い出し、C++でもできるかなーと考え始めたわけです。(某煽り記事が話題になった時に書かれたのでタイトルはあれですが、中身はまじめな技術記事ですので念のため・ω・)

はじめはTemplateで上の記事の内容を真似ようかなと思ったものの、最近のC++ならconstexprがあるからソート処理くらいならそれでできそうだなと考え始めたわけです。

constexprとは

…いろんな記事が出てるので、そちらを見てください。自分もちゃんと使おうと思ったのは初めてなので。。

Visual Studio 2015でも使えるよね ってことはMicrosoftの出してる情報で確認しました。

constexpr (C++)

コンパイル時演算の確認方法

constexprは、コンパイル時に引数の値が決定できる場合はコンパイル時に処理を行います。 一方、実行時まで引数の値が分からない場合には、普通の関数のように振る舞います。 そのため、コンパイルが通ったからといってそれだけではコンパイル時演算できている保証はできません。。

コンパイル時に演算できているかの確認は上記情報によると、

注: Visual Studio デバッガーでは、内部にブレークポイントを挿入することで、constexpr 関数がコンパイル時に評価されているかどうかがわかります。 ブレークポイントにヒットすると、実行時に関数が呼び出されます。 ヒットしなければ、コンパイル時に関数が呼び出されます。

とのこと。翻訳前の英語も確認したけれど、ちゃんと同じ意味のことが書いてありました。

うまくいかない…??

ソートには比較が必須ですからね、まずは値の大小比較をする関数を準備せねば。 ためしに以下のようにコードを書き、実行してみました。 ブレークポイントで止まらないことを確認すればいいんだな。

F5をポチッ

f:id:wkwkhautbois:20160731204731p:plain

……止まった( ・_・)??

おかしい、コンパイル時に値が計算されていたらここに入るはずがない…。

原因として思いついたのは2点

  1. Debugモードでコンパイルしているとコンパイル時演算されない
  2. VC++コンパイラコンパイル時演算してくれない

1つめのDebugモードだからというのは有力だけど、このくらい簡単な計算だとconstexpr指定にしなくても最適化されてインライン展開されてしまうので、ブレークポイントで確認ができないという。 (だったらconstexpr指定しなくても良いという話もある。)

2つめのVC++コンパイラだからというのは、別のコンパイラで試せば分かるはず。 今のVS2015はコンパイラとしてClangを使うことができる。そちらに切り替えると、たしかにブレークポイントで止まらないのでコンパイル時に演算できてそうな雰囲気。

まとめ

少なくともVC++15のコンパイラでは、Debugビルドだとconstexprでも実行時処理になるみたい。

何がいけないのか知ってる人がいたら教えてほしいです。