25

Say we have an implementation of std::aligned_storage. I've defined two macros for the alignof and alignas operators.

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

In the second case I get the error in the title of the question (compiling with Clang, similar error with GCC). The error is not present if I replace the macros with alignof and alignas respectively. Why is this?

Before you start asking me why I'm doing this - the original macros have C++98 compatible code such as __alignof and __attribute__((__aligned__(x))) and those are compiler specific, so macros are my only choice...

EDIT: So according to the question marked as duplicate, an extra set of parenthesis would fix the issue.

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

It doesn't. So, how would I go about doing this? (Satisfiable question?)

6
  • 1
    @melpomene, That doesn't really give any way of working around the problem Commented Jun 25, 2016 at 15:44
  • 1
    Why? Because comma. - Macro expansion sees the comma before making syntactic sense of any other content Commented Jun 25, 2016 at 15:44
  • stackoverflow.com/questions/679979/… may be helpful Commented Jun 25, 2016 at 15:46
  • 1
    btw - simply use #define MACRO(...) something(__VA_ARGS__) to work around it. Commented Jun 25, 2016 at 15:47
  • The extra parens thing only works for expressions. You're dealing with types/parameter lists, so a different workaround is required. Commented Jun 25, 2016 at 15:49

2 Answers 2

34

C/C++ preprocessor is not aware of any C/C++ language constructs, it is just text preprocessor with its own syntax and rules. According to that syntax the following code ALIGNOF(aligned_storage<16, 16>::type) is invocation of macro ALIGNOF with 2 arguments (aligned_storage<16 and 16>::type) because there is comma inside parentheses.

I would suggest you to typedef aligned_storage<16, 16> and use that type inside this macro invocation.

Sign up to request clarification or add additional context in comments.

1 Comment

@melpomene Thank you for editing, I didn't know ** ** doesn't work inside ` ` :) and my reaction was slower than yours :)
12

As has been explained, macro arguments are separated by commas that are not within extra parentheses. There are a few easy-ish ways to get around this, some more general than others:

  1. Use a variadic macro (or a corresponding compiler extension for C++98) (live example):

    #define ALIGNOF(...) alignof(__VA_ARGS__)
    ALIGNOF(aligned_storage<16, 16>::type)
    
  2. Get the caller to pass the number of arguments and wrap the arguments in extra parentheses (live example):

    #define ALIGNOF(n, tuple) alignof(BOOST_PP_TUPLE_ENUM(n, tuple))
    ALIGNOF(2 (aligned_storage<16, 16>::type))
    
  3. Get the caller to pass in a "sequence" (live example):

    #define ALIGNOF(seq) alignof(BOOST_PP_SEQ_ENUM(seq))
    ALIGNOF((aligned_storage<16)(16>::type))
    
  4. If the argument is a type, use a typedef (live example):

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

    Note that templated aliases can be created prior to C++11 by templating a struct and exposing a type member:

    template<int N> 
    struct alias {
        typedef typename aligned_storage<N, N>::type type;
    };
    
  5. If the argument can be used parenthesized, get the caller to wrap the argument in parentheses and use it directly. That is not the case with alignof.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.