2012-11-30 20 views
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 /静态断言!),数组(如strcpy_s),自己的结构有YES,NO类型,什么不是。但找不到解决方案!

我正在使用VC2008。我知道static_assert,decltype等,但不能使用C++ 0x。


EDIT(解决方案):

#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! 
} 

感谢阿恩·默茨为这个可爱的建议。我从中推导出解决方案。 noConstAllowed对于所有T&类型都是过载的,并且如果传递了常量值,则将调用另一个过载。两者都有不同的返回类型,并因此检查大小。模板化版本返回bool,它满足任何传递的变量的断言,并且对任何常量或表达式失败(因为返回类型为int)。

+0

Boost.StaticAssert – 2012-11-30 11:46:04

+0

@aleguna,毫无意义的评论!我需要静态断言的表达式,而不是如何创建或使用静态断言。 – Ajay

回答

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或者其他位置宏,或者你会将它变成一个函数。在yourse中,你只需要使用两行中的一行。

+0

不错的建议!你给出的解决方案不是static-assert,但是对于'noConstAllowed'和sizeof来说,通过重载,模板和不同的返回类型,我会为它创建一个SA。 – Ajay

+0

做成了。谢谢!检查我编辑的问题,找到我找到的解决方案。 – Ajay