2014-07-17 5 views
18

In C++:C++ affermare: la precedenza dell'espressione in un'asserzione macro

assert( std::is_same<int , int>::value ); // does not compile 

    assert((std::is_same<int , int>::value)); // compiles 

Qualcuno può spiegare perché?

+4

Macro semantica disprezzo del compilatore (quelli non esistono ancora quando le macro vengono espanse). Puoi passare praticamente qualsiasi cosa separata da virgole. – chris

+0

Vale la pena notare che queste parentesi sono ciò che rende possibili i quattro [tipi di dati Boost PP] (http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/index.html). – chris

+3

'std :: is_same' è un controllo in fase di compilazione, quindi non ha molto senso fare comunque un asserzione di run-time! Effettua invece una dichiarazione in fase di compilazione. In C++ 11 c'è [static_assert] (http://en.cppreference.com/w/cpp/language/static_assert), altrimenti ci sono ancora [molte opzioni] (http://stackoverflow.com/questions/174356/way-to-assert-espressioni-at-build-time-in-c) –

risposta

11

La virgola viene considerata come un separatore di argomenti per la macro, ma le parentesi nel secondo caso proteggono gli argomenti. Possiamo vedere questo andando al progetto di C++ sezione standard 16.3Macro sostituzione che dice (sottolineatura mia):

La sequenza di token pre-elaborazione delimitate dalla maggior parte al di fuori- parentesi corrispondenti forma l'elenco dei argomenti per la macro di tipo . I singoli argomenti all'interno dell'elenco sono separati dai prefissi della virgola , ma i token di preelaborazione della virgola tra parentesi interne corrispondenti a non separano gli argomenti. Se ci sono sequenze di gettoni preelaborazione nella lista di argomenti che altrimenti fungono da direttive al preprocessore, 154 il comportamento non è definito

Possiamo vedere che macro espansione avviene prima dell'analisi semantica visitando sezione 2.2fasi della traduzione e vedere che la fase 4 è include: vengono eseguiti

direttive

preelaborazione invocazioni macro sono espansi, e [...] Tutte le direttive al preprocessore vengono cancellati .

e la fase 7 include:

[...] Ogni token preelaborazione viene convertito in un token. (2.7). I token risultanti sono sintatticamente e semanticamente analizzati e tradotto come un'unità di traduzione [...]

Come nota a lato possiamo vedere la Boost include una macro speciale per affrontare questa situazione: BOOST_PP_COMMA:

La macro BOOST_PP_COMMA si espande in una virgola.

e dice:

Il preprocessore interpreta le virgole come separatori di argomenti in invocazioni macro. Per questo motivo, le virgole richiedono una gestione speciale.

ed un esempio:

BOOST_PP_IF(1, BOOST_PP_COMMA, BOOST_PP_EMPTY)() // expands to , 
14

assert è una macro di preprocessore. I macro preprocessore sono stupidi; non capiscono i modelli. Il preprocessore vede 10 gettoni all'interno delle parentesi:

assert(std :: is_same < int , int > :: value); 

si divide in virgola. Non sa che questo è il posto sbagliato dove dividere, perché non capisce che std::is_same<int e int>::value non sono espressioni C++ valide.

Il preprocessore è abbastanza intelligente da non rompere i contenuti di coppie interne di parentesi su più argomenti. Ecco perché aggiungere le parentesi aggiuntive risolve il problema.

+5

Anche qui un 'static_assert' è sufficiente:' static_assert (std :: is_same :: value, "oops"); ' – quantdev

+0

Non sono solo i modelli. Né le parentesi né le parentesi proteggono le virgole. Parentesi e citazioni fanno. – rici

+0

Questo non ha molto senso. Il preprocessore ovviamente sa che "assert" si aspetta esattamente un argomento, motivo per cui è in grado di segnalare l'errore in primo luogo. Allora, perché il preprocessore vorrebbe fare qualsiasi scissione? Se asserire fosse una macro che prevedeva due o più argomenti, posso facilmente capire un tentativo di divisione. Ma asserisci che, come entrambi voi, io e il preproduttore sicuramente sappiamo, ci vuole solo un argomento. Quindi è oltre me il motivo per cui il preprocessore si scomoda con un tentativo di divisione della virgola e dimmi che ho dato troppi argomenti. – igbgotiz