やさしいconstexpr(1) - NF
やさしいconstexpr(2) - NF
時間経ってしまったけどつづき
関数にconstexprを指定する(つづき)
前回、constexpr関数を調べました。constexpr関数にすれば、戻り値をコンパイル時定数として扱えるよ、というメリットがありました。他になんかうれしい事あるの?と言う事で、constexpr を使うべき5の理由 - その3 - ボレロ村上 - ENiyGmaA Codeを読む。
参照透明でない関数は、以下のようにグローバルな状態を変更する可能性がある。
constexpr 関数であれば、副作用がないことを明示的に保証することができる。
早速試してみる。constexpr関数の中でグローバル変数を変更してみる。
#include <iostream> size_t N = 10; constexpr void foo(){ N = 11; }; int main() { foo(); std::cout << N; }
あれ…エラーになるのかと思ったけど、予想に反して普通にコンパイルも実行も出来てしまった。これだと、リンク先に書いてある「C:ドライブをフォーマットする実装」も出来てしまうように思える…
と言う訳で、理解してないとこういう疑問が出たりでなかったりする。(サンプル数1づつ)
そもそも副作用ってなに
一般的には意図した作用(=主作用)以外の作用が起こることで、風邪薬飲んだ時に眠くなるみたいな話だと思う。プログラミングにおいては、Wikipediaによると
評価値を得ること(※関数では「引数を受け取り値を返す」と表現する)が主たる作用とされ、それ以外のコンピュータの論理的状態(ローカル環境以外の状態変数の値)を変化させる作用を副作用という
らしい。つまり、意図していても状態を変化させたら副作用と呼ぶようだ。
副作用がありそうなサンプルを書いてみる。foo()は引数を2倍にして返す関数だけど、うっかり(?)メンバ変数Nを書き換えてしまっている、という例。
#include <iostream> class MyArray { public: MyArray(){ N = 0; } size_t foo(const size_t size){ N = size*2; return N; } // 引数を2倍にして返す関数 size_t N; }; int main() { constexpr MyArray arr; std::cout << arr.N << std::endl; std::cout << arr.foo(10) << std::endl; // メンバ変数Nも書き換えている std::cout << arr.N << std::endl; }
ただ、このfoo()にconstexpr を付けても、やはり普通に実行できてしまう。
あかん、全然理解できてないので続く…