我创建了一个小宏元编程库,实现基本的构建体,例如REPEAT(times, x),IF(value, true, false)元组,等等.
我的大多数实现都是通过基于可变参数计数或通过计数器重载宏来实现的:
// Example:
#define REPEAT_0(x)
#define REPEAT_1(x) x REPEAT_0(x)
#define REPEAT_2(x) x REPEAT_1(x)
#define REPEAT_3(x) x REPEAT_2(x)
// ...
// (these defines are generated using an external script)
// ...
#define REPEAT(count, x) CAT(REPEAT_, count)(x)
Run Code Online (Sandbox Code Playgroud)
这很好,但我最近遇到了Paul Fultz的一个非常有趣的宏递归实现.
直到延迟表达部分,我没有理解他的文章.
但是,我在理解使用DEFER和OBSTRUCT正确使用方面遇到了很多麻烦.
Paul实现了一个非常优雅的版本,REPEAT不需要脚本生成的定义,如下所示:
#define EAT(...)
#define EXPAND(...) __VA_ARGS__
#define WHEN(c) IF(c)(EXPAND, EAT)
#define REPEAT(count, macro, ...) \
WHEN(count) \
( \ …Run Code Online (Sandbox Code Playgroud) Visual Studio的失败static_assert的错误消息完全由一个错误代码和static_assert的第二个参数组成,没有任何其他消息表明它是静态断言失败.我想制作一个宏来解决这个问题.例如,作为第一次尝试:
#define STATIC_ASSERT(x) static_assert(x, "static assertion failed: " #x)
Run Code Online (Sandbox Code Playgroud)
您遇到的第一个问题是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;
}
Run Code Online (Sandbox Code Playgroud)
这是非法的,因为第一个中的T和U之间的逗号STATIC_ASSERT被解释为分隔两个宏参数,而不是模板参数.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__)
Run Code Online (Sandbox Code Playgroud)
后一种解决方案更好,只需要更改宏定义.(__VA_ARGS__新定义中的额外括号是为了在某些更奇怪的情况下保持正确的操作顺序.在这个特定的宏中可能无关紧要,但在宏定义中将括号括在宏的参数周围是个好习惯. )
现在,如果我想更改我的 …