【发布时间】:2014-07-23 11:19:33
【问题描述】:
Visual Studio 针对失败的 static_assert 的错误消息完全由一个错误代码和 static_assert 的第二个参数组成,没有任何其他消息表明这是一个静态断言失败。我想做一个宏来解决这个问题。例如,作为第一次尝试:
#define STATIC_ASSERT(x) static_assert(x, "static assertion failed: " #x)
您遇到的第一个问题是 C 预处理器无法将 < > 理解为包含分隔符,这会导致模板出现语法错误。以下内容变为非法:
template <typename T, typename U>
auto SafeMultiply(T x, U y) -> decltype(x * y)
{
STATIC_ASSERT(std::is_same<T, U>::value);
STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
if (x > (std::numeric_limits<decltype(x * y)>::max)())
throw std::overflow_error("multiplication overflow");
return x * y;
}
这是非法的,因为第一个 STATIC_ASSERT 中的 T 和 U 之间的逗号被解释为分隔两个宏参数,而不是模板参数。 C 预处理器抛出错误,因为STATIC_ASSERT 宏只接受一个参数。
这个问题的两个主要解决方案是使用双括号,最近,使用可变参数宏:
// Invoke the macro this way...
STATIC_ASSERT((std::is_same<T, U>::value));
// ...or define it this way:
#define STATIC_ASSERT(...) static_assert((__VA_ARGS__), \
"static assertion failed: " #__VA_ARGS__)
后一种解决方案更好,只需要更改宏定义。 (新定义中__VA_ARGS__ 周围的额外括号是为了在某些更奇怪的情况下保持正确的操作顺序。在这个特定的宏中可能无关紧要,但是在宏的参数周围加上括号是一个好习惯宏定义。)
现在,如果我想更改我的 STATIC_ASSERT 宏以接收标准 C++ static_assert 之类的消息,但在消息中添加前缀,该怎么办?有点像这样,但支持使用std::is_same<T, U>而不使用双括号:
// Causes a syntax error :(
#define STATIC_ASSERT(expr, msg) static_assert((expr), \
"static assertion failed: " msg)
STATIC_ASSERT(std::is_same<T, U>, "x and y are not of the same type");
如果我能得到可变参数宏的最后一个参数,它会起作用:
// I wish this'd work
#define STATIC_ASSERT(..., msg) static_assert((__VA_ARGS__), \
"static assertion failed: " msg)
STATIC_ASSERT(std::is_same<T, U>, "x and y are not of the same type");
但既然这不合法,我怎样才能合法地获取... 宏参数集的最后一个参数?当然,我可以颠倒参数顺序,但它与static_assert不一样。
【问题讨论】:
-
为什么不首先使用
static_assert? -
因为 static_assert 在 Visual C++ 中没有给出类似“静态断言失败”的消息:它只是给出了指定为错误的确切文本。
-
好吧,用
"static assertion failed:"开始你的信息,问题就解决了。作为代码的维护者,如果我遇到这样的宏,我可能会从扯掉它开始;对我来说,这不值得。
标签: c++ c c99 c-preprocessor