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é?
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é?
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.3
Macro 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.2
fasi della traduzione e vedere che la fase 4 è include: vengono eseguiti
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 ,
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.
Anche qui un 'static_assert' è sufficiente:' static_assert (std :: is_same
Non sono solo i modelli. Né le parentesi né le parentesi proteggono le virgole. Parentesi e citazioni fanno. – rici
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
Macro semantica disprezzo del compilatore (quelli non esistono ancora quando le macro vengono espanse). Puoi passare praticamente qualsiasi cosa separata da virgole. – chris
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
'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) –