C ++クラスでアサーションを折りたたむ?
-
18-09-2019 - |
質問
だから、クラス以外のタイプの状況では、私は次のようなことをすることができます:
int val_to_check = 0;
int some_func(int param) {
assert(val_to_check == 0);
return param*param+param;
}
int main() {
printf("Val: %i\n", some_func(rand()));
return 0;
}
もしも val_to_check
宣言されています const
代わりに、コンパイラによってアサーションを折りたたむことができます。
クラスのメンバー変数を使用して同様の一定の折りたたみを得ることができるかどうか興味があります。たとえば、次のようなことをすることはできますか?
class Test {
public:
Test(int val) : val_(val) {}
int some_func(int param) {
assert(val_ == 0);
return param*param+param;
}
private:
const int val_;
};
したがって、クラスが定義されている場合、val_はa-la:
Test my_test(0);
printf("Val: %i\n", my_test.some_func(rand()));
(私はこれらが不自然な例であることを知っています)。アサーションを時々折りたたむことができるはずですが、私がテストした簡単な例はそれをしていないようです。私が得た最高のものは、アサーションコードを関数の終わりに移動することです(w/ -o3をコンパイルするとき)
解決
あなたが提供したクラスの例では、2つのランタイム変数があるため、コンパイラが定数がゼロであると仮定する方法はありません。
- 君の
const int val_
クラスの各インスタンスのみが一定であるため、すべてのケースに対応する必要があるため、クラスの関数コードを最適化することはできません。 - インスタンス化の例は文字通りの定数を提供しません、それはの結果を提供します
rand()
これは可変です。これ 五月 それが唯一のことを知っているなら、それを最適化することが可能ですval_
そのクラスのすべてのインスタンスに提供されることはゼロです。
コンストラクターに定数を提供して、最適化するかどうかを確認しましたか?
他のヒント
C ++では、「定数式」(5.19)の概念があります。これは文字通りの式であり、定数式のみを含む算術式、または一定の式で静的に初期化された変数の値の値です。コンパイラは、コンパイル時にそのような式の値を決定できます。
あなたの場合、 val_
メンバーであるオブジェクトに応じて異なる値を持つ可能性があるため、「一定の式」ではありません。のアウトオブラインバージョン用 some_func
, 、おそらく、コンパイラがそれが一定であることを知ることができないことに同意します。インラインバージョンの場合、 val_
, 、分析されたすべてのコンストラクターの完全なソースコードもあると仮定します。コンパイラがこの分析を行うことができるかどうかは、実装の質の問題です。コンパイラは明らかにできません。
Val_は、すべてのインスタンスではなく、インスタンスのconstです。実際にすべてのインスタンスで同じにしたい場合は、静的constにすることができ、コンパイラがグローバルMade constを使用した最初の例で実際に起こっていることを最適化できるようになります。
サイドノートとして、あなたの例は整数のオーバーフローの影響を受けます。
-O2は私のためにトリックをしているようです:
%cat foo.cxx
#include <cstdio>
#include <cstdlib>
#include <cassert>
class Test {
public:
Test(int val) : val_(val) {}
int some_func(int param) {
assert(val_ == 0);
return param*param+param;
}
private:
const int val_;
};
int main() {
Test my_test(0);
printf("Val: %d\n", my_test.some_func(rand()));
return 0;
}
% g++ -S foo.cxx && grep assert foo.s ; echo $?
.ascii "%s:%u: failed assertion `%s'\12\0"
0
% g++ -O2 -S foo.cxx && grep assert foo.s ; echo $?
1
確かに折りたたまれていると主張したい場合は、boost :: static_assertを調べたいと思うかもしれません。
今、私はむしろ、デザインの基本的な概念に悩まされています。クラスのユーザーが価値を提供することを許可しますが、それが特定の価値でなければならないと主張しています。 1つの値だけが正しい場合、なぜそれらにまったく供給されているのですか?適切な値を使用して、それで終わらないのはなぜですか?
主張の一般的な考えは、その障害が間違った入力のようなものを知らせてはならないということであることに留意してください。プログラム自体の根本的な問題を示すためにのみ使用する必要があります。どこかにロジックが誤っているか、その順序に何かがあることです。
一方、異なる値が許可されている状況に対処しているかもしれませんが、特定の値に対して異なるアクションをとる(または同じアクションを異なる方法で実装する)ことを望んでいます。アサートを折りたたむためには、明らかにコンパイル時定数である必要があります。
その場合、その値は非タイプのテンプレートパラメーターとしてテンプレートを作成することを検討します。特別に実装する値のテンプレートを専門とします。これにより、おおよそあなたが望んでいるように見える効果が得られますが、その値のテストは実行時間ではなくコンパイル時に発生しなければならないという事実を強制します。ランタイムコードを作成し、コンパイラのスマートがコンパイル時間でそれを処理するのに十分なほど希望する代わりに、コンパイルタイムマッチを明示的に書きます。