【问题标题】:Assert integrality of a macro argument断言宏参数的完整性
【发布时间】:2014-11-20 18:57:36
【问题描述】:

我正在尝试创建一个静态断言其参数是严格正整数的宏。这适用于我的许多其他遗留宏,到目前为止,这些宏只是假设没有任何检查其参数的完整性。

简而言之,如果我有如下条目,我希望 static_assert 通过:

“4”、“24”、“42324”等,

如果参数是这样的,我希望 static_assert 失败

“4.0”、“3.00”、“2.99”、“3.01”、“-5”、“45n3mn”、“0”、“01”、“002”等,以及空条目

基本上,只有当宏中的参数是一个干净的整数字符串时,我才希望断言通过,我通过以下“算法”来做到这一点:

(1) 如果字符串化参数不只是数字,则失败

(2) 如果第一个字符为 '0',则失败

(3) 如果为空,则失败

以下是我目前拥有的,但由于错误“C2057:预期的常量表达式”而无法编译(我正在使用 MSVS2013,但也想构建 g++ 4.8 兼容代码)。我不确定如何从 static_assert 中“调用”std::string 方法。

#define MyStaticAssert_isInt(num, message) \
    static_assert(std::string(#num).find_first_not_of("0123456789") == std::string::npos, message) \
    static_assert(std::string(#num).front() != '0', message) \
    static_assert(!std::string(#num).empty(), message)

提前致谢!

【问题讨论】:

  • 我很确定 (2) 里面不应该有“不”:)
  • True...条件 (2) 应声明“如果第一个字符为 '0',则失败”...换句话说,我们不想接受类似于“001”的内容"

标签: c++ c++11 static-assert


【解决方案1】:

你可以试试这个用户定义的文字:

#include <cstddef>
#include <string>

constexpr bool operator ""_pure(char const * s, std::size_t len)
{
  return len == 0 ||
         ('0' <= s[0] && s[0] <= '9' && operator ""_pure(s + 1, len - 1));
}

#define CHECK_INT(X) static_assert(X ## _pure, "Not pure")

int main()
{
  CHECK_INT("123.0");
}

您当然可以将字符串化作为宏的一部分。

【讨论】:

  • +1 很好,我第一次看到 operator "" 递归应用 :)
  • 谢谢克雷克。确实非常优雅。不知道它是否因“0”或空输入而失败
  • @Chrys:不,细节留给你填写。
【解决方案2】:

以下应该允许在编译时检查字符文字:

constexpr bool is_number_cont( const char* str )
{
    return !*str || ( *str >= '0' && *str <= '9' && is_number_cont( str + 1 ) );
}

constexpr bool is_number( const char* str )
{
    return *str >= '1' && *str <= '9' && is_number_cont( str + 1 );
}

int main()
{
    static_assert( is_number( "123" ), "123 failed" );
    static_assert( is_number( "0" ), "0 failed" );
    static_assert( is_number( "" ), "empty string failed" );
    static_assert( is_number( "1.23" ), "1.23 failed" );
    static_assert( is_number( "abc" ), "abc failed" );
}

您可以在任何地方添加检查,包括在宏中。

Live example


如果您被 C++11 之前的编译器卡住,您可以使用手动扩展至有限的固定长度:

#define is_number(S) \
               S[0]>='1' && S[0]<='9' && \
    (!S[1] || (S[1]>='0' && S[1]<='9' && \
    (!S[2] || (S[2]>='0' && S[2]<='9' && \
    (!S[3] || (S[3]>='0' && S[3]<='9' && \
    (!S[4] || (S[4]>='0' && S[4]<='9' && \
     !S[5]))))))))

如果您需要检查更长的字符串,请扩展它,应该很明显如何做到这一点。

Live example

【讨论】:

  • 这是一个很好的解决方案,但恐怕 MSVS 2013 不支持“constexpr”......:(
  • 谢谢。 MSVS 更新的编译器确实支持 constexpr。我将下载并进一步试验...感谢您向我介绍这个概念!
猜你喜欢
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多