我正在使用宏来定义代码中的简单变量(类似这样):
#define foobar 1
//...
barfoo(foobar);
为了防止错误,我想通过验证输入来确保foobar
是一个数字。 foobar
应始终为数字,因此非常简单。
显然,预处理器不处理数学,所以任何用算术生成某种类型错误的希望都会丢失。
我认为常量因为这个原因确实更好,但我正在尝试使用所有宏,因此它在我拥有的配置文件中是一致的(有些需要宏)。正则表达式可能是一个好的解决方法,但是GCC似乎不支持[使用宏]这个(加上, http://xkcd.com/1171/ )。
答案 0 :(得分:5)
在C ++ 11中,有类型特征和静态断言可以满足您的目的:
#include <type_traits>
#define foo 1
// #define foo "bar" // will lead to a compiler error containing the message "foo is not int"
static_assert(std::is_integral<decltype(foo)>::value, "foo is not int");
答案 1 :(得分:2)
由于对问题的评论说不应该禁止表达式,所以涉及编译时检查表达式具有整数类型的答案将不起作用:这将检测{{1}之间没有区别},1
和(1)
,因为这三个都是(0+1)
类型的prvalues,具有完全相同的值。
因此,答案必须涉及查看宏定义本身,并且可以通过对其进行字符串化,并将验证放在带有字符串的int
函数中,并在静态断言中使用它。正十进制非整数整数文字的示例:
constexpr
如果您还需要处理后缀文字(#define A 1
#define B 2
#define C 3
#define D (4)
#define STR_(x) #x
#define STR(x) STR_(x)
constexpr bool is_number(const char *str) {
return (*str >= '0' && *str <= '9') && (str[1] == '\0' || is_number(str+1));
}
#define VERIFY(x) static_assert(is_number(STR(x)), STR(x) " is not a number!")
VERIFY(A); // passes
VERIFY(B); // passes
VERIFY(C); // passes
VERIFY(D); // fails: (4) is not a number!
)或非十进制文字(123L
),则需要进行扩展。如果作为特殊例外,您希望允许将一元0x123
应用于整数文字,那么也需要扩展名。
这几乎肯定不值得保护。如果-
定义为D
,(4)
或(3+1)
,而不是(C+1)
,则有人决定代码更具可读性和/或可维护性,如果除了这一断言之外,这些定义可以很好地起作用,那么断言就会很快被破坏掉。
答案 2 :(得分:1)
我建议你只在必要时使用宏,否则使用常量。一致性并不总是最重要的优先事项。
答案 3 :(得分:0)
为此目的,有充分的理由使用常量而不是定义。
Scott Meyers在他的“Effective C ++”一书中有一章专门讨论这个问题:
http://books.google.com/books?id=U7lTySXdFk0C&pg=PT41&lpg=PT41#v=onepage&q&f=false
第2项:“更喜欢#defines的consts,enums和inlines。”
使用常量可以使调试更容易,因为编译器可以访问名称(而不仅仅是预处理器替换)。
定义也没有相同的类型安全功能(这可能是你试图在这里解决的问题)。它们没有相同的范围特征。