3

前文:

switch(nValue)
{
case X:
...
case Y:
...
default:
   ASSERT_FOR_DEFAULT(nValue);
}

ASSERT_FOR_DEFAULT「デフォルトの場合」のヒットを報告するための(カスタム)アサーションダイアログを表示するマクロです。はい、このマクロは実行時アサーション用であり、コンパイル時アサーション用ではありません。ただし、必要なのは、定数値(コンパイル時)をこのマクロに渡すことはできないということです。

問題:

以下はコンパイル時に失敗するはずです:

ASSERT_FOR_DEFAULT(5);

はい、プログラマーは、のdefault場合だけでなく、どこでも使用できますswitch-case。彼は、で使用されていない任意の式を使用することもできますswitch。しかし、それは問題ではありません。非定数のみをこのマクロに渡す必要があります。

このマクロについて書かれた重要なことは何もありません。ただASSERT/であると仮定してassertください。

テンプレート(他のSFINAE / static-assertsを使用しました!)、配列(などstrcpy_s)、独自の構造体YESNOタイプなどを試してみました。しかし、解決策を見つけることができませんでした!

私はVC2008を使用しています。static_assert、などは知ってdecltypeいますが、C++0xは使えません。


編集(解決策):

#define STATIC_ASSERT(expr) {int array[!!(expr)]; expr;}

template <class T>  
bool noConstAllowed(T&);

int noConstAllowed(...);

#define ASSERT_FOR_DEFAULT_VALUE(val)                \
{                                                  \
    STATIC_ASSERT(sizeof(noConstAllowed(val))==sizeof(bool));   \
}

int main()
{
    int test=10;

    ASSERT_FOR_DEFAULT_VALUE(test);
    ASSERT_FOR_DEFAULT_VALUE(2);
    ASSERT_FOR_DEFAULT_VALUE(test+2);  //FAILS, but okay for me! 
}

この素敵な提案をしてくれたArneMertzに感謝します。私はそれから解決策を導き出しました。 noConstAllowedはすべてのT&タイプでオーバーロードされ、定数値が渡されると、別のオーバーロードが呼び出されます。どちらもリターンタイプが異なるため、サイズをチェックします。テンプレート化されたバージョンは、bool渡された変数のアサートを満たし、定数または式では失敗するを返します(戻り型はint)であるため。

4

1 に答える 1

3

パラメータのアドレスを取得するようにマクロを再定義できます-これはリテラルでは失敗するはずです。ただし、定数変数を渡すことを妨げるものではありません。

const static int FIVE = 5;
ASSERT_FOR_DEFAULT(FIVE); // still works.

すべて種類の定数がマクロに渡されないようにするには、非 const 参照によってパラメーターを受け取る関数を呼び出します。

template <class T>  void noConstAllowed(T&){};
#define ASSERT_FOR_DEFAULT_VALUE(val)                \
  {                                                  \
    (void*)&(val);         /* no literals*/          \
    noConstAllowed(val);   /* no constants at all */ \
    switchHitDefaultDialog(val, __FILE__, __LINE__); \
  }

FILEやその他の位置マクロなどを使用するか、それを関数にしたと思います。そのうち、2 つの行のうちの 1 つだけを使用する必要があります。

于 2012-11-30T12:42:48.720 に答える