如何检索 C99 可变参数宏的最后一个参数?

2024-04-15

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;
}

这是非法的,因为第一个 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__)

后一种解决方案更好,只需更改宏定义即可。 (多余的括号__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");

但由于这是不合法的,我如何合法地获取 a 的最后一个参数...宏参数设置?当然,我可以颠倒参数顺序,但它与static_assert.


在完全一般的情况下,没有简单的方法来获取最后一个宏参数,但是您可以轻松实现一个版本,该版本可以获取参数列表的最后一个元素,达到某个预定的最大值。对于现实世界的代码来说,像 64 个参数这样的参数通常就足够了。

您需要做的就是计算传递的参数数量,然后返回元素N-1从列表中:

// count arguments
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N

// utility (concatenation)
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B

#define M_GET_ELEM(N, ...) M_CONC(M_GET_ELEM_, N)(__VA_ARGS__)
#define M_GET_ELEM_0(_0, ...) _0
#define M_GET_ELEM_1(_0, _1, ...) _1
#define M_GET_ELEM_2(_0, _1, _2, ...) _2
#define M_GET_ELEM_3(_0, _1, _2, _3, ...) _3
#define M_GET_ELEM_4(_0, _1, _2, _3, _4, ...) _4
#define M_GET_ELEM_5(_0, _1, _2, _3, _4, _5, ...) _5
#define M_GET_ELEM_6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define M_GET_ELEM_7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
#define M_GET_ELEM_8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define M_GET_ELEM_9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define M_GET_ELEM_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) _10

// Get last argument - placeholder decrements by one
#define M_GET_LAST(...) M_GET_ELEM(M_NARGS(__VA_ARGS__), _, __VA_ARGS__ ,,,,,,,,,,,)

您可以通过几分钟的复制和粘贴将其扩展到您想要的有限数量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何检索 C99 可变参数宏的最后一个参数? 的相关文章

随机推荐

  • rspec - 为什么仅在 ubuntu 上,当它们相同时,使用 assert_equal 进行此属性比较会失败?

    两个测试都失败了 但仅在 Ubuntu 12 上失败 但在我的 新 Mac 上却失败了 失败的两个是 Active Record 对象属性比较 但我尽了最大努力来比较它们 例如在命令行创建哈希并粘贴属性 比较表明它们是相同的 这是一个真正的
  • Airflow initdb slot_pool 不存在

    我面临一个问题airflowpostgres 后端初始化 乌班图 18 04 1 气流 v1 10 6 Postgres 10 10 Python 3 6 当我跑步时 airflow initdb I get 2019 11 22 10 1
  • 在本例中如何避免 VBA 中的 select/active 语句?

    需要导出一个PDF文件中的所有工作表 所以我找到了这段代码 它有效 导出一个PDF 每张工作表一个页面 但我不想使用 select active 语句 我更喜欢使用存储对象的变量 问题 如何避免此代码中的 select ActiveShee
  • WPF MVVM 可观察集合不更新 GUI

    我正在设计一个 MVVM WPF 应用程序 并且有一个 ViewModel 它有一个名为 SelectedCustomer 的属性 类型为 Customer 该对象有一个名为 SummaryDetails 的 ObservableColle
  • 如何在 GWT 的 Jetty 中启用 HTTPS?

    如何在 GWT 附带的 Jetty 中启用 HTTPS gwt dev jar 中 隐藏 了一个 README SSL txt 你可以找到最新版本在 Github 上 https github com gwtproject gwt blob
  • (Fortify) 类别:Android 不良做法:缺少 Google Play 服务更新的安全提供程序(1 期)

    我们正在使用 Fortify 扫描我的 Android 源代码 但我无法摆脱这个问题 类别 Android 不良做法 缺少 Google Play 服务更新的安全提供程序 1 期 Fortify指向这行代码 工具 替换 android al
  • Numpy 沿特定维度选择不替换

    在不进行替换的情况下 我根据指定的分布从样本中 n 次不同地选择 k 个元素 迭代解决方案很简单 for in range n np random choice a size k replace False p p 我无法设置size k
  • Java:如何通过忽略“\n”来逐行读取文件

    我正在尝试读取每行制表符分隔的文本文件行 行通过使用回车符 r n 进行分隔 并且在制表符分隔的文本字段中允许使用换行符 n 由于我想每行读取文件行 因此我希望我的程序忽略独立的 n 很遗憾 BufferedReader使用这两种可能性来分
  • std::this_thread::yield 与 Linux 上的 sched_yield 有什么不同吗?

    我只是想知道如何std this thread yield是在linux上实现的 它与sched yield 我见过一些自旋锁的实现 这意味着std this thread yield是更轻量级的东西sched yield就线程放弃进程多长
  • OSGi 应用程序修补策略

    修补 OSGi 容器的适当机制是什么 1 Should the bundles binaries jars have the same name as the old ones then a Replace the bundle with
  • 使用多线程的 JPA 中的事务

    我的目标是使用单元测试在我的应用程序中引发乐观锁定异常 我已经在理论上了解了如何做到这一点 但我在实践中的问题是如何维护两个线程之间的事务 所以 这就是我到目前为止所做的 我正在使用 JUnit 测试 RunWith SpringJUnit
  • 用于进行修改的 git 工作流程,您永远不会将其推回原点

    我正在构建一个 iPhone 应用程序PhoneGap http phonegap com 其中有一个 Git 存储库 我想在我自己的 Git 存储库中跟踪对 PhoneGap 代码的更改 主要是向 www 目录添加文件 同时能够从 Pho
  • GitHub、Gerrit、Hudson(Jenkins) 工作流程

    我刚刚开始一起使用 GitHub Gerrit 和 Hudson Jenkins 我需要一些关于工作流程的想法 我们想使用 GitHub 作为我们的主要远程存储库 我们希望主要使用 Gerrit 进行代码审查 但也用于 Hudson 中的构
  • 如何运行 Webpack 开发服务器 --https --hot --inline

    使用 CLI 配置时 有没有办法在 https 上运行 webpack dev server 问题是连接到socket io结束了http并不是https 存在解决方法 但非常烦人 手动包含https webpack dev server在
  • Scala - 以函数方式修改字符串

    我刚刚开始使用 Scala 因此开始以更实用的方式做事 只是想知道是否有一种更实用的方法来实现如下所示的功能 def expand exp String String var result exp for k v lt libMap res
  • Python/Django 中的音频波形可视化

    我已经在 Stack Overflow 上寻找这个问题的答案 但似乎没有地方给出正确的答案或方向 我的项目将允许用户上传 WAV 最终将在服务器上使用 FFmpeg 将其转换为低质量 MP3 并将全部存储在 Amazon S3 上并提供服务
  • asp.net mvc - ActionLink 的渲染不一致

    我有一个控制器 它接受以下两种格式的 URL 网络 添加或编辑 gt 在页面上呈现空白表单以添加新的网络对象 网络 AddOrEdit id gt 使用预填充表单呈现页面以编辑网络对象 带有 ID id 显然 每个实例中都使用相同的视图 我
  • 在 JavaScript 中逐行动态添加字幕到视频元素

    我想知道目前是否可行 下面是我的 HTML
  • Chrome DevTools 中缺少“添加到主屏幕”链接

    使用 Google 服务可能会令人沮丧 他们有令人难以置信的文档 但文档总是假设一切正常 如果有什么东西不像广告上说的那样有效 那你就完全靠自己了 没有错误消息 没有解决问题的帮助 甚至没有承认某些事情可能不起作用 以防万一 添加到主屏幕
  • 如何检索 C99 可变参数宏的最后一个参数?

    Visual Studio 失败的 static assert 错误消息完全由错误代码和 static assert 的第二个参数组成 没有任何其他消息表明这是静态断言失败 我想做一个宏来解决这个问题 例如 作为第一次尝试 define S