1

セットアップの例を次に示します。マクロまたはテンプレートCHECKEXPR_RETURNVAL(EXPR、VAL)は、VALを返すときにEXPRがTRUEであることを確認します。

これは、次の非常に単純化された例のように、さまざまな場所で役立ちます。

#define ISPOW2(VAL)           ((0!=VAL)&&(0==(VAL&(VAL-1))))
#define _ALIGNPOW2(VAL,ALIGN) ((VAL+(ALIGN-1))&(~(ALIGN-1)))

#define ALIGNPOW2(VAL,ALIGN)  CHECKEXPR_RETURNVAL( \
    ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )

したがって、難しさは次のとおり です。可能であればコンパイル時のチェックを実行し、値がコンパイル時に決定される定数でない場合は、ランタイムチェックを実行します。

基本的に、アイデアは悪いパラメータをできるだけ早くキャッ​​チすることです。コンパイル時に不良パラメータをキャッチできる場合は、実行時に検出するよりも優れています。また、定数初期化子にはコンパイル時バージョンが必要です。


これが、単一バージョンを複数の場所で機能させるための2つの(失敗した)試みです(一定の配列サイズとして、列挙型初期化子として、および変数を持つ関数として)。残念ながら、これらはコンパイル時のみ(一定の初期化子)またはランタイムのみで機能します。両方で機能するバージョンを見つけたいと思います。

// CHECKEXPR_RETURNVAL - version "A"
#define CTCHECK_EXPR(EXP)(CTCheckBool<EXP>::ExistsZeroIfTrue)
template <bool bExpression> struct CTCheckBool {};
template <> struct CTCheckBool<true> {enum{ExistsZeroIfTrue=0};};
// Note: Plus ("+") is used rather than comma operator because
// the comma operator can not be used for constant initializers
#define CHECKEXPR_RETURNVAL_A(EXP,VAL) (CTCHECK_EXPR(EXP) + (VAL))

// Test Out version "A" -- works only for Compile Time Constants
#define ALIGNPOW2_A(VAL,ALIGN)  CHECKEXPR_RETURNVAL_A( \
    ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )

char AlignedVar_A[ALIGNPOW2_A(2,8)];
enum { AlignedVal_A = ALIGNPOW2_A(57,16) };

int TestAlignPow2_A(int val, int align)
    {return(ALIGNPOW2_A(val,align));}       // Compile Error


// CHECKEXPR_RETURNVAL - version "B"
template<typename T> T CHECKEXPR_RETURNVAL_B(bool bExpr,T val)
    { ASSERT(bExpr); return(val); }

// Test Out version "B" -- works only for Runtime Computed Values
#define ALIGNPOW2_B(VAL,ALIGN)  CHECKEXPR_RETURNVAL_B( \
    ISPOW2(ALIGN) , _ALIGNPOW2(VAL,ALIGN) )

char AlignedVar_B[ALIGNPOW2_B(2,8)];        // Compile Error
enum { AlignedVal_B = ALIGNPOW2_B(57,16) }; // Compile Error

int TestAlignPow2_B(int val, int align)
    {return(ALIGNPOW2_B(val,align));}

残念ながら、どちらのバージョンも3つのケースすべてで機能しません。すべての場合に機能するコード構造はありますか?

4

2 に答える 2

0

本当にc++0x関数を利用するようですconstexpr...

于 2010-08-03T22:29:23.373 に答える
0

まあ...完全な答えではありませんが、これからあなたが望むものを導き出すことができると思います:

#include <stdio.h>

template <int I> struct S{
    static void doIt(){
        fprintf(stderr, "wow\n");
    }
};

template<> void S<0>::doIt(){
    fprintf(stderr, "oops\n");
}

#define EXPR(p) S<(int)((bool)(p))>::doIt()     

int main(int argc, char** argv){
    EXPR((5+2)==7);
    EXPR((5+2)==8);
    const int a = 58;
    EXPR(a==58);
    EXPR(58);
    return 0;
}

式に基づいてコンパイラ エラーが発生する可能性があります。

#include <stdio.h>

template <int I> struct S{
    static void doIt(){
        ssdfkjehiu //deliberately invalid code
        fprintf(stderr, "oops\n");
    }
};

template<> void S<1>::doIt(){
    fprintf(stderr, "wow\n");
}

#define EXPR(p) S<(int)((bool)(p))>::doIt() 



int main(int argc, char** argv){
    EXPR((5+2)==7);
    EXPR((5+2)==8);//uncomment it to make code compile
    const int a = 58;
    EXPR(a==58);
    EXPR(58);
    return 0;
}

ただし、エラーの原因となる行は、長いテンプレート エラー メッセージの途中にあります。例:

1.cpp(6) : error C2065: 'asdlfkjhasd' : undeclared identifier
        1.cpp(4) : while compiling class template member function 'void S<I>::doIt(void)'
        with
        [
            I=0
        ]
        1.cpp(19) : see reference to class template instantiation 'S<I>' being compiled
        with
        [
            I=0
        ]
1.cpp(6) : error C2146: syntax error : missing ';' before identifier 'fprintf'

ご覧のとおり、メッセージの途中に記載されている 19 行目でエラーが発生しています。これは少し不便です。

両方の例が未定義の C++ の動作に依存していないことは保証できません。

また、次のコードメンテナーはこれに満足しないかもしれないと思います...

PSブーストも検討する必要があると思います。私の記憶が正しければ、かなり多くの「マジック プリプロセッサ マクロ」(ループなど) が含まれていたので、似たようなものを実装していた可能性があります。

--編集--
さて、これはどうですか?:

#include <stdio.h>
#include <string>

template <typename T> void a(T &i){
    fprintf(stderr, "variable\n");  
}

void a(const char* const i){
    fprintf(stderr, "constant\n");
}

void a(bool i){
    fprintf(stderr, "constant\n");
}

int main(int argc, char** argv){
    int i;
    float f;
    std::string s;
    const char* s1 = "b";
    a(3);
    a(3+2);
    a(1.0f);
    a('a');
    a("b");
    a(i);
    a(f);
    a(s);
    a(s1);
    return 0;
}
于 2010-08-03T23:28:28.607 に答える