2016-06-25 26 views
10

Supponiamo di avere un'implementazione di std::aligned_storage. Ho definito due macro per gli operatori alignof e alignas.Troppi argomenti forniti per l'invocazione di macro come funzione

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

Nel secondo caso ottengo l'errore nel titolo della questione (la compilazione con Clang, errore simile con GCC). L'errore non è presente se sostituisco le macro con alignof e alignas rispettivamente. Perché è questo?

Prima di iniziare a me perché sto facendo questo chiedendo - le macro originali hanno codice compatibile C++ 98, come __alignof e __attribute__((__aligned__(x))) e questi sono compilatore specifico, in modo macro sono la mia unica scelta ...

MODIFICA: Quindi, in base alla domanda contrassegnata come duplicata, una serie aggiuntiva di parentesi risolverebbe il problema.

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

Non funziona. Quindi, come potrei fare questo? (Domanda soddisfacente?)

+1

@melpomene, che non dà davvero alcun modo di aggirare il problema – chris

+1

Perché? Perché virgola. - L'espansione macro vede la virgola prima di dare un senso sintattico a qualsiasi altro contenuto –

+0

http://stackoverflow.com/questions/679979/how-to-make-a-variadic-macro-variable-number-of-arguments può essere utile –

risposta

13

Il preprocessore C/C++ non è a conoscenza di alcun costrutto del linguaggio C/C++, è solo un preprocessore di testo con una propria sintassi e regole. In base a tale sintassi, il seguente codice ALIGNOF(aligned_storage<16, 16>::type) è la chiamata della macro ALIGNOF con 2 argomenti (aligned_storage<16 e 16>::type) perché tra parentesi c'è una virgola.

Ti suggerisco di typedefaligned_storage<16, 16> e utilizzare quel tipo all'interno di questa macro invocazione.

+0

@melpomene Grazie per il montaggio, non sapevo ** ** non funziona all'interno di '' :) e la mia reazione è stata più lenta della tua :) – mvidelgauz

8

Come è stato spiegato, gli argomenti macro sono separati da virgole che non sono tra parentesi aggiuntive. Ci sono alcuni semplici modi-ish per aggirare questo, un po 'più generale rispetto ad altri:

  1. utilizza una macro variadic (o una corrispondente estensione compilatore per C++ 98) (live example):

    #define ALIGNOF(...) alignof(__VA_ARGS__) 
    ALIGNOF(aligned_storage<16, 16>::type) 
    
  2. Prendi il chiamante per passare il numero di argomenti e avvolgere gli argomenti tra parentesi in più (live example):

    #define ALIGNOF(n, tuple) alignof(BOOST_PP_TUPLE_ENUM(n, tuple)) 
    ALIGNOF(2 (aligned_storage<16, 16>::type)) 
    
  3. Prendi il ca ller passare in una "sequenza" (live example):

    #define ALIGNOF(seq) alignof(BOOST_PP_SEQ_ENUM(seq)) 
    ALIGNOF((aligned_storage<16)(16>::type)) 
    
  4. Se l'argomento è un tipo, utilizzare un typedef (live example):

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

    noti che alias su modelli possono essere creati prima C++ 11 da dima di una struttura ed esponendo un membro type:

    template<int N> 
    struct alias { 
        typedef typename aligned_storage<N, N>::type type; 
    }; 
    
  5. Se l'argomento può essere utilizzato tra parentesi, ottenere il chiamante per racchiudere l'argomento tra parentesi e utilizzarlo direttamente. Questo non è il caso di alignof.

Problemi correlati