【问题标题】:Too many arguments provided to function-like macro invocation [duplicate]为类似函数的宏调用提供了太多参数[重复]
【发布时间】:2016-10-28 01:20:53
【问题描述】:

假设我们有一个std::aligned_storage 的实现。我为alignofalignas 运算符定义了两个宏。

#include <iostream>
#include <cstddef>

#define ALIGNOF(x) alignof(x)
#define ALIGNAS(x) alignas(x)

template<std::size_t N, std::size_t Al = ALIGNOF(std::max_align_t)>
struct aligned_storage
{
    struct type {
        ALIGNAS(Al) unsigned char data[N];
    };
};

int main()
{
    // first case
    std::cout << ALIGNOF(aligned_storage<16>::type); // Works fine

    // second case
    std::cout << ALIGNOF(aligned_storage<16, 16>::type); // compiler error
}

在第二种情况下,我得到问题标题中的错误(使用 Clang 编译,使用 GCC 时出现类似错误)。如果我分别用alignofalignas 替换宏,则该错误不存在。 这是为什么?

在你开始问我为什么要这样做之前 - 原始宏具有 C++98 兼容代码,例如 __alignof__attribute__((__aligned__(x))) 并且这些是特定于编译器的,所以宏是我唯一的选择...

编辑: 因此,根据标记为重复的问题,额外的一组括号将解决该问题。

std::cout << ALIGNOF((aligned_storage<16, 16>::type)); // compiler error

它没有。 那么,我该怎么做呢? (令人满意的问题?)

【问题讨论】:

  • @melpomene,这并不能真正解决问题
  • 为什么?因为逗号。 - 宏扩展在对任何其他内容产生句法意义之前看到逗号
  • 顺便说一句 - 只需使用 #define MACRO(...) something(__VA_ARGS__) 来解决它。
  • 额外的括号仅适用于表达式。您正在处理类型/参数列表,因此需要不同的解决方法。

标签: c++ macros


【解决方案1】:

C/C++ 预处理器不知道任何 C/C++ 语言结构,它只是具有自己的语法和规则的文本预处理器。根据该语法,以下代码 ALIGNOF(aligned_storage&lt;16, 16&gt;::type) 是使用 2 个参数(aligned_storage&lt;1616&gt;::type)调用宏 ALIGNOF,因为括号内有逗号。

我建议您 typedef aligned_storage&lt;16, 16&gt; 并在此宏调用中使用该类型。

【讨论】:

  • @melpomene 感谢您的编辑,我不知道 ** ** 在 ` ` 中不起作用 :) 我的反应比你慢 :)
【解决方案2】:

如前所述,宏参数由不在额外括号内的逗号分隔。有一些简单的方法可以解决这个问题,其中一些比其他方法更通用:

  1. 使用可变参数宏(或 C++98 的相应编译器扩展)(live example):

    #define ALIGNOF(...) alignof(__VA_ARGS__)
    ALIGNOF(aligned_storage<16, 16>::type)
    
  2. 让调用者传递参数的数量并将参数包装在额外的括号中(live example):

    #define ALIGNOF(n, tuple) alignof(BOOST_PP_TUPLE_ENUM(n, tuple))
    ALIGNOF(2 (aligned_storage<16, 16>::type))
    
  3. 让调用者传入一个“序列”(live example):

    #define ALIGNOF(seq) alignof(BOOST_PP_SEQ_ENUM(seq))
    ALIGNOF((aligned_storage<16)(16>::type))
    
  4. 如果参数是类型,请使用typedef (live example):

    typedef aligned_storage<16, 16>::type storage_t;
    ALIGNOF(storage_t)
    

    请注意,在 C++11 之前,可以通过模板化结构并公开 type 成员来创建模板化别名:

    template<int N> 
    struct alias {
        typedef typename aligned_storage<N, N>::type type;
    };
    
  5. 如果参数可以使用括号,让调用者将参数包装在括号中并直接使用它。 alignof 并非如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多