1

したがって、クラス以外のタイプの状況では、次のようなことができます。

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()));

(私はこれらが不自然な例であることを知っています)。アサーションを折りたたむことは時々可能であるように思われますが、私がテストした単純な例ではそれができないようです。私が得た最善の方法は、アサーションコードを関数の最後に移動することです(-O3を使用してコンパイルする場合)

4

5 に答える 5

2

C ++には、「定数式」(5.19)の概念があります。これは、リテラル式、定数式のみを含む算術式、または定数式で静的に初期化された変数の値です。コンパイラーは、コンパイル時にそのような式の値を判別できます。

あなたの場合、val_は「定数式」ではありません。これは、メンバーであるオブジェクトによって値が異なる可能性があるためです。のアウトオブラインバージョンのsome_func場合、コンパイラがそれが定数であることを認識できないことにおそらく同意するでしょう。val_インラインバージョンの場合、すべてのコンストラクターの完全なソースコードも分析されていると仮定すると、の値を決定できます。コンパイラがこの分析を実行できるかどうかは、実装の品質の問題です。コンパイラは明らかに実行できません。

于 2009-09-28T01:53:02.630 に答える
2

提供したクラスの例では、2つの実行時変数があるため、コンパイラーが定数がゼロであると想定する方法はありません。

  • const int val_クラスのインスタンスごとに定数のみであるため、すべてのケースに対応する必要があるため、クラスの関数コードを最適化することはできません。
  • インスタンス化の例では、リテラル定数は提供されません。結果rand()は可変です。そのクラスのすべてのインスタンスに提供されるのはゼロであることがわかっている場合は、最適化できる可能性があります。val_

コンストラクターに定数を提供して、それが最適化されるかどうかを確認しましたか?

于 2009-09-28T01:48:53.507 に答える
0

val_は、すべてのインスタンスではなく、インスタンスのconstです。実際にすべてのインスタンスで同じにしたい場合は、静的constにすることができます。これにより、コンパイラーはそれを最適化できます。これは、グローバルに作成されたconstを使用した最初の例で実際に起こっていることです。

ちなみに、あなたの例は整数のオーバーフローの影響を受けます。

于 2009-09-28T01:58:19.557 に答える
0

-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
于 2009-09-28T02:00:59.690 に答える
0

確実に折りたたまれているというアサーションが必要な場合は、boost::static_assertを検索することをお勧めします。

今のところ、私はデザインの基本的な概念にかなり悩まされています。クラスのユーザーが値を指定できるようにしているのに、それは1つの特定の値でなければならないと主張しているのです。1つの値だけが正しい場合、なぜそれらはそれをまったく供給しないのですか?正しい値を使用してそれで済ませてみませんか?

アサーションの一般的な考え方は、その失敗が誤った入力のようなものを示すべきではないということを覚えておいてください。これは、プログラム自体の根本的な問題を通知するためにのみ使用する必要があります。つまり、どこかに障害のあるロジックがあるか、その順序で何かが発生しているということです。

一方、異なる値が許可されているが、1つの特定の値に対して異なるアクションを実行する(または同じアクションを異なる方法で実装する)状況を扱っている場合があります。アサーションを折りたたむには、明らかにコンパイル時定数である必要があります。

その場合は、その値を非型テンプレートパラメーターとして使用してテンプレートを作成することを検討します。特別に実装する値に合わせてテンプレートを特殊化します。これにより、おおよそあなたが望むように見える効果が得られますが、その値のテストは実行時ではなくコンパイル時に行われる必要があるという事実が強制されます。ランタイムコードを記述し、コンパイラがコンパイル時にそれを処理するのに十分賢いことを期待する代わりに、コンパイル時の一致を明示的に記述します。

于 2009-09-28T03:09:41.470 に答える