提供给类似函数的宏调用的参数太多

时间:2016-06-25 15:32:27

标签: c++ macros

假设我们有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

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

2 个答案:

答案 0 :(得分:18)

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

我建议您typedef aligned_storage<16, 16>并在此宏调用中使用该类型。

答案 1 :(得分:9)

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

  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. 让来电者通过&#34;序列&#34; (live example):

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

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

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

    template<int N> 
    struct alias {
        typedef typename aligned_storage<N, N>::type type;
    };
    
  5. 如果参数可以使用括号,请让调用者将参数括在括号中并直接使用它。 alignof没有这种情况。