質問

プリプロセッサでプリコンパイル計算を行うためにboost_ppを使用しています。コードサイズがあるアプリケーションに焦点を当てています 非常に 私にとって重要です。 (だから、コンパイラを言わないでください したほうがいい また いつもの それは、コンパイル時に実行されるものと生成されるコードを制御する必要があります)。ただし、整数定数と変数の両方にマクロ/関数の同じ名前を使用できるようにしたいと考えています。些細な例として、私は持つことができます

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

これは私が望んでいることをします、

int a = 10;

コンパイル時間中。

しかし、私もそれを使用してほしい

int b = 5;
int a = TWICE(b);

これは前処理する必要があります

int b = 5;
int a = 5 * 2;

もちろん、私は従来のマクロを次のように使用することでそうすることができます

#define TWICE(n) n * 2

しかし、それは私が整数定数に対してやりたいことをしません(コンパイル時間中にそれらを評価します)。

ですから、私の質問は、引数が文字通りであるか変数であるかを確認し、異なる定義を使用するトリックがあるということです。つまり、このようなもの:

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

編集:それで、私が本当に目指しているのは、コンパイル時に何かが一定であるかどうかを確認する方法であり、したがって、boost_pp_関数の良い議論です。これは、ほとんどの人がプリプロセッサと一般的なプログラミングの推奨事項から期待するものとは異なることを理解しています。しかし、ノーはありません 間違い プログラミングの方法なので、その哲学に同意しない場合は、質問を嫌ってはいけません。 Boost_ppライブラリが存在する理由があり、この質問は同じ精神にあります。しかし、それは不可能かもしれません。

役に立ちましたか?

解決

コンパイラの最適化により任された方が良いことをしようとしています。

int main (void) {
  int b = 5;
  int a = b * 2;

  return a; // return it so we use a and it's not optimized away
}

GCC -O3 -S TC

 .file "t.c"
 .text
 .p2align 4,,15
.globl main
 .type main, @function
main:
.LFB0:
 .cfi_startproc
 movl $10, %eax
 ret
 .cfi_endproc
.LFE0:
 .size main, .-main
 .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
 .section .note.GNU-stack,"",@progbits

コンパイラの最適化が最適化されます。

編集:コンパイラーが「通常」や「通常」がそうするべきだと聞きたくないことを知っています。ただし、あなたがやろうとしていることは、C Preprocessorで行われることを意図したものではありません。 C言語とCプリプロセッサを設計した人々は、それが基本原子であるため、前処理トークンと連携するように設計しました。 CPPは、多くの点で「愚か」です。これは悪いことではありません(実際、これは多くの場合、それを非常に便利にしているのです)が、結局のところ、それはプリプロセッサです。ソースファイルが解析される前にソースファイルを事前に処理します。セマンティック分析が発生する前に、ソースファイルをプレセシングします。特定のソースファイルの有効性がチェックされる前に、ソースファイルを事前に処理します。これは、これがパーサーとセマンティックアナライザーが処理すべきか、通常行うべきものであると聞きたくないことを理解しています。しかし、これは状況の現実です。信じられないほど小さいコードを設計したい場合は、作業を行うためにプリプロセッサコンストラクトを作成しようとする代わりに、コンパイラに頼って仕事をする必要があります。このように考えてみてください。何千時間もの仕事がコンパイラに入ったので、できるだけ多くの作業を再利用してみてください!

他のヒント

ただし、直接的なアプローチではありません。

struct operation {
    template<int N>
    struct compile {
        static const int value = N;
    };
    static int runtime(int N) { return N; }
};

operation::compile<5>::value;
operation::runtime(5);

または、または

operation<5>();
operation(5);

2つのレベルを混合する本当のチャンスはありません(プリプロセッサと評価 変数)。私があなたの質問から理解していることから、 b 象徴的な定数である必要がありますか?

伝統的なものを使うべきだと思います

#define TWICE(n) ((n) * 2)

ただし、式で変数を初期化する代わりに、タイム定数をコンパイルして初期化する必要があります。コンパイル時間で評価を強制し、Cにシンボリック定数を持つことを強制する唯一のものは、積分列挙定数です。これらはタイプがあると定義されています int コンパイル時に評価されます。

enum { bInit = 5 };
int b = bInit;
enum { aInit = TWICE(bInit) };
int a = aInit; 

そして一般的に、あなたはあまりにもrif約してはいけません const (あなたについて b)そして、生成されたアセンブラーを確認します -S.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top